From c66249b79aa9bfa0924494adcd5345b5b1244b0c Mon Sep 17 00:00:00 2001 From: tpearson Date: Wed, 10 Feb 2010 01:02:50 +0000 Subject: Added old abandoned KDE3 version of gwenview git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/gwenview@1088034 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- AUTHORS | 73 + COPYING | 339 + COPYING-DOCS | 397 + INSTALL | 167 + Mainpage.dox | 11 + Makefile.am | 10 + Makefile.am.in | 9 + NEWS | 863 ++ README | 85 + acinclude.m4 | 12406 +++++++++++++++++++++ aclocal.m4 | 913 ++ config.h.in | 273 + configure.files | 4 + configure.in | 290 + configure.in.bot | 4 + configure.in.in | 141 + doc/Makefile.am | 2 + doc/browse_mode.png | Bin 0 -> 134206 bytes doc/dock_grip.png | Bin 0 -> 566 bytes doc/docked_windows.docbook | 70 + doc/external_tools.docbook | 69 + doc/external_tools_dialog.png | Bin 0 -> 14063 bytes doc/index.docbook | 64 + doc/interface.docbook | 50 + doc/introduction.docbook | 27 + doc/keybindings.docbook | 21 + doc/mouse.docbook | 41 + doc/view_mode.png | Bin 0 -> 38274 bytes src/CREDITS | 88 + src/DESIGN | 142 + src/HACKING | 95 + src/Makefile.am | 8 + src/app/.vimrc | 4 + src/app/Makefile.am | 56 + src/app/bookmarkdialog.cpp | 115 + src/app/bookmarkdialog.h | 54 + src/app/bookmarkdialogbase.ui | 109 + src/app/bookmarkowner.cpp | 53 + src/app/bookmarkowner.h | 53 + src/app/bookmarkviewcontroller.cpp | 415 + src/app/bookmarkviewcontroller.h | 93 + src/app/configdialog.cpp | 306 + src/app/configdialog.h | 65 + src/app/configfileoperationspage.ui | 173 + src/app/configfullscreenpage.ui | 144 + src/app/configimagelistpage.ui | 294 + src/app/configimageviewpage.ui | 330 + src/app/configmiscpage.ui | 204 + src/app/configslideshowpage.ui | 134 + src/app/dirviewcontroller.cpp | 143 + src/app/dirviewcontroller.h | 71 + src/app/gwenviewui.rc | 133 + src/app/history.cpp | 137 + src/app/history.h | 71 + src/app/kipiinterface.cpp | 224 + src/app/kipiinterface.h | 62 + src/app/main.cpp | 163 + src/app/mainwindow.cpp | 1371 +++ src/app/mainwindow.h | 222 + src/app/metaedit.cpp | 138 + src/app/metaedit.h | 59 + src/app/testvtabwidget.cpp | 48 + src/app/treeview.cpp | 342 + src/app/treeview.h | 70 + src/app/truncatedtextlabel.h | 79 + src/app/vtabwidget.cpp | 85 + src/app/vtabwidget.h | 52 + src/configure.in.bot | 11 + src/desktopfiles/Makefile.am | 9 + src/desktopfiles/gwenview.desktop | 107 + src/desktopfiles/konqgwenview.desktop | 55 + src/doc/Makefile.am | 1 + src/doc/gwenview.1 | 238 + src/gvcore/.vimrc | 4 + src/gvcore/Makefile.am | 85 + src/gvcore/archive.cpp | 87 + src/gvcore/archive.h | 46 + src/gvcore/bcgdialog.cpp | 84 + src/gvcore/bcgdialog.h | 53 + src/gvcore/bcgdialogbase.ui | 179 + src/gvcore/busylevelmanager.cpp | 108 + src/gvcore/busylevelmanager.h | 113 + src/gvcore/cache.cpp | 402 + src/gvcore/cache.h | 67 + src/gvcore/captionformatter.cpp | 57 + src/gvcore/captionformatter.h | 57 + src/gvcore/clicklineedit.cpp | 106 + src/gvcore/clicklineedit.h | 63 + src/gvcore/cursortracker.cpp | 86 + src/gvcore/cursortracker.h | 56 + src/gvcore/deletedialog.cpp | 133 + src/gvcore/deletedialog.h | 55 + src/gvcore/deletedialogbase.ui | 111 + src/gvcore/document.cpp | 618 + src/gvcore/document.h | 194 + src/gvcore/documentanimatedloadedimpl.cpp | 97 + src/gvcore/documentanimatedloadedimpl.h | 62 + src/gvcore/documentimpl.cpp | 103 + src/gvcore/documentimpl.h | 103 + src/gvcore/documentjpegloadedimpl.cpp | 143 + src/gvcore/documentjpegloadedimpl.h | 62 + src/gvcore/documentloadedimpl.cpp | 198 + src/gvcore/documentloadedimpl.h | 54 + src/gvcore/documentloadingimpl.cpp | 165 + src/gvcore/documentloadingimpl.h | 55 + src/gvcore/documentotherloadedimpl.cpp | 58 + src/gvcore/documentotherloadedimpl.h | 52 + src/gvcore/dragpixmapgenerator.h | 179 + src/gvcore/externaltoolaction.cpp | 56 + src/gvcore/externaltoolaction.h | 50 + src/gvcore/externaltoolcontext.cpp | 80 + src/gvcore/externaltoolcontext.h | 59 + src/gvcore/externaltooldialog.cpp | 355 + src/gvcore/externaltooldialog.h | 59 + src/gvcore/externaltooldialogbase.ui | 373 + src/gvcore/externaltoolmanager.cpp | 294 + src/gvcore/externaltoolmanager.h | 67 + src/gvcore/filedetailview.cpp | 552 + src/gvcore/filedetailview.h | 133 + src/gvcore/filedetailviewitem.cpp | 70 + src/gvcore/filedetailviewitem.h | 89 + src/gvcore/fileoperation.cpp | 119 + src/gvcore/fileoperation.h | 95 + src/gvcore/fileoperationconfig.kcfg | 22 + src/gvcore/fileoperationconfig.kcfgc | 7 + src/gvcore/fileopobject.cpp | 347 + src/gvcore/fileopobject.h | 143 + src/gvcore/filethumbnailview.cpp | 866 ++ src/gvcore/filethumbnailview.h | 131 + src/gvcore/filethumbnailviewitem.cpp | 394 + src/gvcore/filethumbnailviewitem.h | 69 + src/gvcore/fileviewbase.h | 47 + src/gvcore/fileviewconfig.kcfg | 62 + src/gvcore/fileviewconfig.kcfgc | 7 + src/gvcore/fileviewcontroller.cpp | 1321 +++ src/gvcore/fileviewcontroller.h | 256 + src/gvcore/filterbar.ui | 255 + src/gvcore/fullscreenbar.cpp | 171 + src/gvcore/fullscreenbar.h | 56 + src/gvcore/fullscreenconfig.kcfg | 16 + src/gvcore/fullscreenconfig.kcfgc | 7 + src/gvcore/gimp.h | 138 + src/gvcore/imageframe.h | 42 + src/gvcore/imageloader.cpp | 917 ++ src/gvcore/imageloader.h | 123 + src/gvcore/imagesavedialog.cpp | 131 + src/gvcore/imagesavedialog.h | 53 + src/gvcore/imageview.cpp | 1469 +++ src/gvcore/imageview.h | 190 + src/gvcore/imageviewconfig.kcfg | 54 + src/gvcore/imageviewconfig.kcfgc | 7 + src/gvcore/imageviewcontroller.cpp | 527 + src/gvcore/imageviewcontroller.h | 84 + src/gvcore/imageviewtools.cpp | 213 + src/gvcore/imageviewtools.h | 96 + src/gvcore/inputdialog.cpp | 78 + src/gvcore/inputdialog.h | 55 + src/gvcore/jpegformattype.cpp | 527 + src/gvcore/jpegformattype.h | 51 + src/gvcore/libgwenview_export.h | 36 + src/gvcore/mimetypeutils.cpp | 87 + src/gvcore/mimetypeutils.h | 47 + src/gvcore/miscconfig.kcfg | 31 + src/gvcore/miscconfig.kcfgc | 7 + src/gvcore/mngformattype.cpp | 520 + src/gvcore/mngformattype.h | 55 + src/gvcore/pngformattype.cpp | 559 + src/gvcore/pngformattype.h | 63 + src/gvcore/printdialog.cpp | 297 + src/gvcore/printdialog.h | 80 + src/gvcore/printdialogpagebase.ui | 408 + src/gvcore/qxcfi.cpp | 2405 ++++ src/gvcore/qxcfi.h | 332 + src/gvcore/slideshow.cpp | 217 + src/gvcore/slideshow.h | 86 + src/gvcore/slideshowconfig.kcfg | 27 + src/gvcore/slideshowconfig.kcfgc | 7 + src/gvcore/threadgate.cpp | 60 + src/gvcore/threadgate.h | 45 + src/gvcore/thumbnaildetailsdialog.cpp | 78 + src/gvcore/thumbnaildetailsdialog.h | 47 + src/gvcore/thumbnaildetailsdialogbase.ui | 117 + src/gvcore/thumbnailloadjob.cpp | 763 ++ src/gvcore/thumbnailloadjob.h | 211 + src/gvcore/thumbnailsize.h | 42 + src/gvcore/timeutils.cpp | 53 + src/gvcore/timeutils.h | 44 + src/gvcore/xcursor.cpp | 190 + src/gvcore/xcursor.h | 37 + src/gvcore/xpm.cpp | 439 + src/gvcore/xpm.h | 54 + src/gvdirpart/Makefile.am | 23 + src/gvdirpart/cr16-app-gvdirpart.png | Bin 0 -> 768 bytes src/gvdirpart/cr22-app-gvdirpart.png | Bin 0 -> 1111 bytes src/gvdirpart/cr32-app-gvdirpart.png | Bin 0 -> 1823 bytes src/gvdirpart/crsc-app-gvdirpart.svg | 587 + src/gvdirpart/gvdirpart.cpp | 288 + src/gvdirpart/gvdirpart.desktop | 44 + src/gvdirpart/gvdirpart.h | 174 + src/gvdirpart/gvdirpart.rc | 46 + src/gvdirpart/gvdirpartconfig.kcfg | 10 + src/gvdirpart/gvdirpartconfig.kcfgc | 4 + src/gvdirpart/hi16-app-gvdirpart.png | Bin 0 -> 828 bytes src/gvdirpart/hi22-app-gvdirpart.png | Bin 0 -> 1259 bytes src/gvdirpart/hi32-app-gvdirpart.png | Bin 0 -> 1839 bytes src/gvdirpart/hisc-app-gvdirpart.svg | 226 + src/gvimagepart/Makefile.am | 20 + src/gvimagepart/gvimagepart.cpp | 450 + src/gvimagepart/gvimagepart.desktop | 48 + src/gvimagepart/gvimagepart.h | 181 + src/gvimagepart/gvimagepart.rc | 40 + src/gvimagepart/gvimagepartpopup.rc | 7 + src/imageutils/Makefile.am | 36 + src/imageutils/README | 2 + src/imageutils/asm_scale.S | 810 ++ src/imageutils/croppedqimage.cpp | 77 + src/imageutils/croppedqimage.h | 42 + src/imageutils/imageutils.cpp | 211 + src/imageutils/imageutils.h | 49 + src/imageutils/jinclude.h | 91 + src/imageutils/jpegcontent.cpp | 666 ++ src/imageutils/jpegcontent.h | 86 + src/imageutils/jpegerrormanager.h | 61 + src/imageutils/jpegint.h | 392 + src/imageutils/orient6.jpg | Bin 0 -> 8828 bytes src/imageutils/orientation.h | 58 + src/imageutils/scale.cpp | 1979 ++++ src/imageutils/testjpegcontent.cpp | 256 + src/imageutils/transupp.c | 928 ++ src/imageutils/transupp.h | 141 + src/pics/Makefile.am | 1 + src/pics/action/Makefile.am | 2 + src/pics/action/hi16-action-dnd1.png | Bin 0 -> 126 bytes src/pics/action/hi16-action-dnd2.png | Bin 0 -> 275 bytes src/pics/action/hi16-action-dnd3.png | Bin 0 -> 144 bytes src/pics/action/hi16-action-dnd4.png | Bin 0 -> 275 bytes src/pics/action/hi16-action-dnd5.png | Bin 0 -> 162 bytes src/pics/action/hi16-action-dnd6.png | Bin 0 -> 222 bytes src/pics/action/hi16-action-dnd7.png | Bin 0 -> 196 bytes src/pics/action/hi16-action-dnd8.png | Bin 0 -> 197 bytes src/pics/action/hi16-action-flip.png | Bin 0 -> 686 bytes src/pics/action/hi16-action-mirror.png | Bin 0 -> 636 bytes src/pics/action/hi16-action-rotate_left.png | Bin 0 -> 745 bytes src/pics/action/hi16-action-rotate_right.png | Bin 0 -> 779 bytes src/pics/action/hi16-action-slideshow_pause.png | Bin 0 -> 979 bytes src/pics/action/hi16-action-slideshow_play.png | Bin 0 -> 988 bytes src/pics/action/hi22-action-flip.png | Bin 0 -> 886 bytes src/pics/action/hi22-action-mirror.png | Bin 0 -> 820 bytes src/pics/action/hi22-action-rotate_left.png | Bin 0 -> 1014 bytes src/pics/action/hi22-action-rotate_right.png | Bin 0 -> 1038 bytes src/pics/action/hi22-action-slideshow_pause.png | Bin 0 -> 1483 bytes src/pics/action/hi22-action-slideshow_play.png | Bin 0 -> 1533 bytes src/pics/action/hi32-action-flip.png | Bin 0 -> 1317 bytes src/pics/action/hi32-action-mirror.png | Bin 0 -> 1180 bytes src/pics/action/hi32-action-rotate_left.png | Bin 0 -> 1487 bytes src/pics/action/hi32-action-rotate_right.png | Bin 0 -> 1524 bytes src/pics/action/hi32-action-slideshow_pause.png | Bin 0 -> 2535 bytes src/pics/action/hi32-action-slideshow_play.png | Bin 0 -> 2626 bytes src/pics/action/hi48-action-flip.png | Bin 0 -> 1946 bytes src/pics/action/hi48-action-mirror.png | Bin 0 -> 1907 bytes src/pics/action/hi48-action-rotate_left.png | Bin 0 -> 2329 bytes src/pics/action/hi48-action-rotate_right.png | Bin 0 -> 2429 bytes src/pics/action/hi48-action-slideshow_pause.png | Bin 0 -> 4355 bytes src/pics/action/hi48-action-slideshow_play.png | Bin 0 -> 4490 bytes src/pics/action/hisc-action-slideshow_pause.svgz | Bin 0 -> 3476 bytes src/pics/action/hisc-action-slideshow_play.svgz | Bin 0 -> 3138 bytes src/pics/action/imageops.svg | 189 + src/pics/action/imageops.svgz | Bin 0 -> 1861 bytes src/pics/app/Makefile.am | 1 + src/pics/app/hi128-app-gwenview.png | Bin 0 -> 14250 bytes src/pics/app/hi16-app-gwenview.png | Bin 0 -> 900 bytes src/pics/app/hi22-app-gwenview.png | Bin 0 -> 1327 bytes src/pics/app/hi32-app-gwenview.png | Bin 0 -> 2204 bytes src/pics/app/hi48-app-gwenview.png | Bin 0 -> 3893 bytes src/pics/app/hi64-app-gwenview.png | Bin 0 -> 5745 bytes src/pics/app/hisc-app-gwenview.svgz | Bin 0 -> 2925 bytes src/pics/cursor/Makefile.am | 2 + src/pics/cursor/zoom.png | Bin 0 -> 352 bytes src/pics/thumbnail/Makefile.am | 2 + src/pics/thumbnail/wait.png | Bin 0 -> 214 bytes src/spec/gwenview-RH.spec | 86 + src/spec/gwenview-SuSE.spec | 45 + src/spec/gwenview-mdk.spec | 466 + src/tools/Makefile.am | 3 + src/tools/gimp.desktop | 37 + src/tools/kolourpaint.desktop | 7 + src/tools/konqueror.desktop | 10 + src/tools/tiledwallpaper.desktop | 43 + src/tools/wallpaper.desktop | 45 + src/tsthread/Makefile.am | 12 + src/tsthread/tsthread.cpp | 194 + src/tsthread/tsthread.h | 387 + src/tsthread/tswaitcondition.cpp | 60 + src/tsthread/tswaitcondition.h | 72 + src/updates/Makefile.am | 9 + src/updates/gwenview_1.4_osdformat.sh | 43 + src/updates/gwenview_1.4_osdformat.upd | 4 + src/updates/gwenview_1.4_osdformat_test.sh | 39 + src/updates/gwenview_thumbnail_size.sh | 12 + src/updates/gwenview_thumbnail_size.upd | 5 + stamp-h.in | 0 subdirs | 2 + 302 files changed, 55888 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 COPYING-DOCS create mode 100644 INSTALL create mode 100644 Mainpage.dox create mode 100644 Makefile.am create mode 100644 Makefile.am.in create mode 100644 NEWS create mode 100644 README create mode 100644 acinclude.m4 create mode 100644 aclocal.m4 create mode 100644 config.h.in create mode 100644 configure.files create mode 100644 configure.in create mode 100644 configure.in.bot create mode 100644 configure.in.in create mode 100644 doc/Makefile.am create mode 100644 doc/browse_mode.png create mode 100644 doc/dock_grip.png create mode 100644 doc/docked_windows.docbook create mode 100644 doc/external_tools.docbook create mode 100644 doc/external_tools_dialog.png create mode 100644 doc/index.docbook create mode 100644 doc/interface.docbook create mode 100644 doc/introduction.docbook create mode 100644 doc/keybindings.docbook create mode 100644 doc/mouse.docbook create mode 100644 doc/view_mode.png create mode 100644 src/CREDITS create mode 100644 src/DESIGN create mode 100644 src/HACKING create mode 100644 src/Makefile.am create mode 100644 src/app/.vimrc create mode 100644 src/app/Makefile.am create mode 100644 src/app/bookmarkdialog.cpp create mode 100644 src/app/bookmarkdialog.h create mode 100644 src/app/bookmarkdialogbase.ui create mode 100644 src/app/bookmarkowner.cpp create mode 100644 src/app/bookmarkowner.h create mode 100644 src/app/bookmarkviewcontroller.cpp create mode 100644 src/app/bookmarkviewcontroller.h create mode 100644 src/app/configdialog.cpp create mode 100644 src/app/configdialog.h create mode 100644 src/app/configfileoperationspage.ui create mode 100644 src/app/configfullscreenpage.ui create mode 100644 src/app/configimagelistpage.ui create mode 100644 src/app/configimageviewpage.ui create mode 100644 src/app/configmiscpage.ui create mode 100644 src/app/configslideshowpage.ui create mode 100644 src/app/dirviewcontroller.cpp create mode 100644 src/app/dirviewcontroller.h create mode 100644 src/app/gwenviewui.rc create mode 100644 src/app/history.cpp create mode 100644 src/app/history.h create mode 100644 src/app/kipiinterface.cpp create mode 100644 src/app/kipiinterface.h create mode 100644 src/app/main.cpp create mode 100644 src/app/mainwindow.cpp create mode 100644 src/app/mainwindow.h create mode 100644 src/app/metaedit.cpp create mode 100644 src/app/metaedit.h create mode 100644 src/app/testvtabwidget.cpp create mode 100644 src/app/treeview.cpp create mode 100644 src/app/treeview.h create mode 100644 src/app/truncatedtextlabel.h create mode 100644 src/app/vtabwidget.cpp create mode 100644 src/app/vtabwidget.h create mode 100644 src/configure.in.bot create mode 100644 src/desktopfiles/Makefile.am create mode 100644 src/desktopfiles/gwenview.desktop create mode 100644 src/desktopfiles/konqgwenview.desktop create mode 100644 src/doc/Makefile.am create mode 100644 src/doc/gwenview.1 create mode 100644 src/gvcore/.vimrc create mode 100644 src/gvcore/Makefile.am create mode 100644 src/gvcore/archive.cpp create mode 100644 src/gvcore/archive.h create mode 100644 src/gvcore/bcgdialog.cpp create mode 100644 src/gvcore/bcgdialog.h create mode 100644 src/gvcore/bcgdialogbase.ui create mode 100644 src/gvcore/busylevelmanager.cpp create mode 100644 src/gvcore/busylevelmanager.h create mode 100644 src/gvcore/cache.cpp create mode 100644 src/gvcore/cache.h create mode 100644 src/gvcore/captionformatter.cpp create mode 100644 src/gvcore/captionformatter.h create mode 100644 src/gvcore/clicklineedit.cpp create mode 100644 src/gvcore/clicklineedit.h create mode 100644 src/gvcore/cursortracker.cpp create mode 100644 src/gvcore/cursortracker.h create mode 100644 src/gvcore/deletedialog.cpp create mode 100644 src/gvcore/deletedialog.h create mode 100644 src/gvcore/deletedialogbase.ui create mode 100644 src/gvcore/document.cpp create mode 100644 src/gvcore/document.h create mode 100644 src/gvcore/documentanimatedloadedimpl.cpp create mode 100644 src/gvcore/documentanimatedloadedimpl.h create mode 100644 src/gvcore/documentimpl.cpp create mode 100644 src/gvcore/documentimpl.h create mode 100644 src/gvcore/documentjpegloadedimpl.cpp create mode 100644 src/gvcore/documentjpegloadedimpl.h create mode 100644 src/gvcore/documentloadedimpl.cpp create mode 100644 src/gvcore/documentloadedimpl.h create mode 100644 src/gvcore/documentloadingimpl.cpp create mode 100644 src/gvcore/documentloadingimpl.h create mode 100644 src/gvcore/documentotherloadedimpl.cpp create mode 100644 src/gvcore/documentotherloadedimpl.h create mode 100644 src/gvcore/dragpixmapgenerator.h create mode 100644 src/gvcore/externaltoolaction.cpp create mode 100644 src/gvcore/externaltoolaction.h create mode 100644 src/gvcore/externaltoolcontext.cpp create mode 100644 src/gvcore/externaltoolcontext.h create mode 100644 src/gvcore/externaltooldialog.cpp create mode 100644 src/gvcore/externaltooldialog.h create mode 100644 src/gvcore/externaltooldialogbase.ui create mode 100644 src/gvcore/externaltoolmanager.cpp create mode 100644 src/gvcore/externaltoolmanager.h create mode 100644 src/gvcore/filedetailview.cpp create mode 100644 src/gvcore/filedetailview.h create mode 100644 src/gvcore/filedetailviewitem.cpp create mode 100644 src/gvcore/filedetailviewitem.h create mode 100644 src/gvcore/fileoperation.cpp create mode 100644 src/gvcore/fileoperation.h create mode 100644 src/gvcore/fileoperationconfig.kcfg create mode 100644 src/gvcore/fileoperationconfig.kcfgc create mode 100644 src/gvcore/fileopobject.cpp create mode 100644 src/gvcore/fileopobject.h create mode 100644 src/gvcore/filethumbnailview.cpp create mode 100644 src/gvcore/filethumbnailview.h create mode 100644 src/gvcore/filethumbnailviewitem.cpp create mode 100644 src/gvcore/filethumbnailviewitem.h create mode 100644 src/gvcore/fileviewbase.h create mode 100644 src/gvcore/fileviewconfig.kcfg create mode 100644 src/gvcore/fileviewconfig.kcfgc create mode 100644 src/gvcore/fileviewcontroller.cpp create mode 100644 src/gvcore/fileviewcontroller.h create mode 100644 src/gvcore/filterbar.ui create mode 100644 src/gvcore/fullscreenbar.cpp create mode 100644 src/gvcore/fullscreenbar.h create mode 100644 src/gvcore/fullscreenconfig.kcfg create mode 100644 src/gvcore/fullscreenconfig.kcfgc create mode 100644 src/gvcore/gimp.h create mode 100644 src/gvcore/imageframe.h create mode 100644 src/gvcore/imageloader.cpp create mode 100644 src/gvcore/imageloader.h create mode 100644 src/gvcore/imagesavedialog.cpp create mode 100644 src/gvcore/imagesavedialog.h create mode 100644 src/gvcore/imageview.cpp create mode 100644 src/gvcore/imageview.h create mode 100644 src/gvcore/imageviewconfig.kcfg create mode 100644 src/gvcore/imageviewconfig.kcfgc create mode 100644 src/gvcore/imageviewcontroller.cpp create mode 100644 src/gvcore/imageviewcontroller.h create mode 100644 src/gvcore/imageviewtools.cpp create mode 100644 src/gvcore/imageviewtools.h create mode 100644 src/gvcore/inputdialog.cpp create mode 100644 src/gvcore/inputdialog.h create mode 100644 src/gvcore/jpegformattype.cpp create mode 100644 src/gvcore/jpegformattype.h create mode 100644 src/gvcore/libgwenview_export.h create mode 100644 src/gvcore/mimetypeutils.cpp create mode 100644 src/gvcore/mimetypeutils.h create mode 100644 src/gvcore/miscconfig.kcfg create mode 100644 src/gvcore/miscconfig.kcfgc create mode 100644 src/gvcore/mngformattype.cpp create mode 100644 src/gvcore/mngformattype.h create mode 100644 src/gvcore/pngformattype.cpp create mode 100644 src/gvcore/pngformattype.h create mode 100644 src/gvcore/printdialog.cpp create mode 100644 src/gvcore/printdialog.h create mode 100644 src/gvcore/printdialogpagebase.ui create mode 100644 src/gvcore/qxcfi.cpp create mode 100644 src/gvcore/qxcfi.h create mode 100644 src/gvcore/slideshow.cpp create mode 100644 src/gvcore/slideshow.h create mode 100644 src/gvcore/slideshowconfig.kcfg create mode 100644 src/gvcore/slideshowconfig.kcfgc create mode 100644 src/gvcore/threadgate.cpp create mode 100644 src/gvcore/threadgate.h create mode 100644 src/gvcore/thumbnaildetailsdialog.cpp create mode 100644 src/gvcore/thumbnaildetailsdialog.h create mode 100644 src/gvcore/thumbnaildetailsdialogbase.ui create mode 100644 src/gvcore/thumbnailloadjob.cpp create mode 100644 src/gvcore/thumbnailloadjob.h create mode 100644 src/gvcore/thumbnailsize.h create mode 100644 src/gvcore/timeutils.cpp create mode 100644 src/gvcore/timeutils.h create mode 100644 src/gvcore/xcursor.cpp create mode 100644 src/gvcore/xcursor.h create mode 100644 src/gvcore/xpm.cpp create mode 100644 src/gvcore/xpm.h create mode 100644 src/gvdirpart/Makefile.am create mode 100644 src/gvdirpart/cr16-app-gvdirpart.png create mode 100644 src/gvdirpart/cr22-app-gvdirpart.png create mode 100644 src/gvdirpart/cr32-app-gvdirpart.png create mode 100644 src/gvdirpart/crsc-app-gvdirpart.svg create mode 100644 src/gvdirpart/gvdirpart.cpp create mode 100644 src/gvdirpart/gvdirpart.desktop create mode 100644 src/gvdirpart/gvdirpart.h create mode 100644 src/gvdirpart/gvdirpart.rc create mode 100644 src/gvdirpart/gvdirpartconfig.kcfg create mode 100644 src/gvdirpart/gvdirpartconfig.kcfgc create mode 100644 src/gvdirpart/hi16-app-gvdirpart.png create mode 100644 src/gvdirpart/hi22-app-gvdirpart.png create mode 100644 src/gvdirpart/hi32-app-gvdirpart.png create mode 100644 src/gvdirpart/hisc-app-gvdirpart.svg create mode 100644 src/gvimagepart/Makefile.am create mode 100644 src/gvimagepart/gvimagepart.cpp create mode 100644 src/gvimagepart/gvimagepart.desktop create mode 100644 src/gvimagepart/gvimagepart.h create mode 100644 src/gvimagepart/gvimagepart.rc create mode 100644 src/gvimagepart/gvimagepartpopup.rc create mode 100644 src/imageutils/Makefile.am create mode 100644 src/imageutils/README create mode 100644 src/imageutils/asm_scale.S create mode 100644 src/imageutils/croppedqimage.cpp create mode 100644 src/imageutils/croppedqimage.h create mode 100644 src/imageutils/imageutils.cpp create mode 100644 src/imageutils/imageutils.h create mode 100644 src/imageutils/jinclude.h create mode 100644 src/imageutils/jpegcontent.cpp create mode 100644 src/imageutils/jpegcontent.h create mode 100644 src/imageutils/jpegerrormanager.h create mode 100644 src/imageutils/jpegint.h create mode 100644 src/imageutils/orient6.jpg create mode 100644 src/imageutils/orientation.h create mode 100644 src/imageutils/scale.cpp create mode 100644 src/imageutils/testjpegcontent.cpp create mode 100644 src/imageutils/transupp.c create mode 100644 src/imageutils/transupp.h create mode 100644 src/pics/Makefile.am create mode 100644 src/pics/action/Makefile.am create mode 100644 src/pics/action/hi16-action-dnd1.png create mode 100644 src/pics/action/hi16-action-dnd2.png create mode 100644 src/pics/action/hi16-action-dnd3.png create mode 100644 src/pics/action/hi16-action-dnd4.png create mode 100644 src/pics/action/hi16-action-dnd5.png create mode 100644 src/pics/action/hi16-action-dnd6.png create mode 100644 src/pics/action/hi16-action-dnd7.png create mode 100644 src/pics/action/hi16-action-dnd8.png create mode 100644 src/pics/action/hi16-action-flip.png create mode 100644 src/pics/action/hi16-action-mirror.png create mode 100644 src/pics/action/hi16-action-rotate_left.png create mode 100644 src/pics/action/hi16-action-rotate_right.png create mode 100644 src/pics/action/hi16-action-slideshow_pause.png create mode 100644 src/pics/action/hi16-action-slideshow_play.png create mode 100644 src/pics/action/hi22-action-flip.png create mode 100644 src/pics/action/hi22-action-mirror.png create mode 100644 src/pics/action/hi22-action-rotate_left.png create mode 100644 src/pics/action/hi22-action-rotate_right.png create mode 100644 src/pics/action/hi22-action-slideshow_pause.png create mode 100644 src/pics/action/hi22-action-slideshow_play.png create mode 100644 src/pics/action/hi32-action-flip.png create mode 100644 src/pics/action/hi32-action-mirror.png create mode 100644 src/pics/action/hi32-action-rotate_left.png create mode 100644 src/pics/action/hi32-action-rotate_right.png create mode 100644 src/pics/action/hi32-action-slideshow_pause.png create mode 100644 src/pics/action/hi32-action-slideshow_play.png create mode 100644 src/pics/action/hi48-action-flip.png create mode 100644 src/pics/action/hi48-action-mirror.png create mode 100644 src/pics/action/hi48-action-rotate_left.png create mode 100644 src/pics/action/hi48-action-rotate_right.png create mode 100644 src/pics/action/hi48-action-slideshow_pause.png create mode 100644 src/pics/action/hi48-action-slideshow_play.png create mode 100644 src/pics/action/hisc-action-slideshow_pause.svgz create mode 100644 src/pics/action/hisc-action-slideshow_play.svgz create mode 100644 src/pics/action/imageops.svg create mode 100644 src/pics/action/imageops.svgz create mode 100644 src/pics/app/Makefile.am create mode 100644 src/pics/app/hi128-app-gwenview.png create mode 100644 src/pics/app/hi16-app-gwenview.png create mode 100644 src/pics/app/hi22-app-gwenview.png create mode 100644 src/pics/app/hi32-app-gwenview.png create mode 100644 src/pics/app/hi48-app-gwenview.png create mode 100644 src/pics/app/hi64-app-gwenview.png create mode 100644 src/pics/app/hisc-app-gwenview.svgz create mode 100644 src/pics/cursor/Makefile.am create mode 100644 src/pics/cursor/zoom.png create mode 100644 src/pics/thumbnail/Makefile.am create mode 100644 src/pics/thumbnail/wait.png create mode 100644 src/spec/gwenview-RH.spec create mode 100644 src/spec/gwenview-SuSE.spec create mode 100644 src/spec/gwenview-mdk.spec create mode 100644 src/tools/Makefile.am create mode 100644 src/tools/gimp.desktop create mode 100644 src/tools/kolourpaint.desktop create mode 100644 src/tools/konqueror.desktop create mode 100644 src/tools/tiledwallpaper.desktop create mode 100644 src/tools/wallpaper.desktop create mode 100644 src/tsthread/Makefile.am create mode 100644 src/tsthread/tsthread.cpp create mode 100644 src/tsthread/tsthread.h create mode 100644 src/tsthread/tswaitcondition.cpp create mode 100644 src/tsthread/tswaitcondition.h create mode 100644 src/updates/Makefile.am create mode 100755 src/updates/gwenview_1.4_osdformat.sh create mode 100644 src/updates/gwenview_1.4_osdformat.upd create mode 100755 src/updates/gwenview_1.4_osdformat_test.sh create mode 100644 src/updates/gwenview_thumbnail_size.sh create mode 100644 src/updates/gwenview_thumbnail_size.upd create mode 100644 stamp-h.in create mode 100644 subdirs diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..31407e2 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,73 @@ +DEVELOPERS +---------- + + Aurlien Gteau + + Lubos Lunak + + + +THIRD PARTY CODE +---------------- + +Gwenview includes code from the Imlib2 library. Imlib2 copyright follows: +""" +Copyright (C) 2000 Carsten Haitzler and various contributors + +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, sublicense, 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 of the Software and its Copyright notices. In addition publicly +documented acknowledgment must be given that this software has been used if no +source code of this software is made available publicly. This includes +acknowledgments in either Copyright notices, Manuals, Publicity and Marketing +documents or any documentation provided with any product containing this +software. This License does not apply to any software that links to the +libraries provided by this software (statically or dynamically), but only to +the software provided. + +Please see the COPYING.PLAIN for a plain-english explanation of this notice +and it's intent. + +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. +""" + + +Gwenview includes code from Daniel M. Duley . Copyright +follows: +""" +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. +""" + + +Gwenview includes code from the libjpeg library, developed by "the Independent +JPEG Group". diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..6f5fd5f --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Steet, Fifth Floor, Boston, MA 02111-1307 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. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the 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 Steet, 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. + + , 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 0000000..4a0fe1c --- /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/INSTALL b/INSTALL new file mode 100644 index 0000000..cf92abe --- /dev/null +++ b/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/Mainpage.dox b/Mainpage.dox new file mode 100644 index 0000000..2aa67f9 --- /dev/null +++ b/Mainpage.dox @@ -0,0 +1,11 @@ +/** @mainpage Extragear - Graphics +* +* The Graphics Extragear contains the following applications: +* +* - digikam +* - gwenview +* - kphotoalbum +* - kst +* - showimg +* +*/ diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..dcf59c5 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,10 @@ +# COMPILE_BEFORE_digikamimageplugins = digikam + +AUTOMAKE_OPTIONS = foreign 1.6.1 + +include admin/deps.am +include admin/Doxyfile.am + + +$(top_srcdir)/acinclude.m4: +SUBDIRS=$(TOPSUBDIRS) diff --git a/Makefile.am.in b/Makefile.am.in new file mode 100644 index 0000000..aa68529 --- /dev/null +++ b/Makefile.am.in @@ -0,0 +1,9 @@ +COMPILE_BEFORE_digikamimageplugins = digikam + +AUTOMAKE_OPTIONS = foreign 1.6.1 + +include admin/deps.am +include admin/Doxyfile.am + +$(top_srcdir)/acinclude.m4: $(top_srcdir)/*/*.m4 + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..831e93e --- /dev/null +++ b/NEWS @@ -0,0 +1,863 @@ +2007.09.15 - v1.4.2 +- New features: + - Settings in the dialog to edit the thumbnail view details are now directly + applied, no need to click "Apply" anymore. + - OSD can now display more image information: aperture, focal length, iso and + exposure time. Patch by Carles Pina i Estany. +- Fixes: + - Bug 123516: After renaming, thumbnail panel is not updated + - Bug 138467: Crash in Exiv2 readMetadata when reading image saved in Photoshop + - Bug 131162: Autorotate images preference setting is forgotten + - Bug 132556: Gwenview asks to save the wrong file if the modified file is read-only + - Bug 111641: When several printing images in a row, "Keep Ratio" keeps ratio of first image + - Avoid crash when viewing extremely large images. + - Fix optimization compiler flags being disabled for scaling code. + - In fullscreen mode, make sure the cursor does not come back after moving to + the next image. Patch by Carles Pina i Estany. + - Bug 130511: In the KParts, make Gwenview translations the active one, to + avoid using KDELibs instead. + +2006.11.26 - v1.4.1 +- New features: + - Show preview of images when dragging them. + - Added "back/forward/reload/save as" actions to the KPart context menu + (Bug 127560). +- Fixes: + - Fix crash when showing current folder properties from context menu (Bug + 129890). + - Load JPEG rotated images using the right rotation directly instead of + loading them first and rotate them after (Bug 117173). + - Do not show the name of the current file in the status bar: it's already + shown in the title bar and it was causing the mainwindow to be enlarged if + the name was very long (Bug 127004). + - Show the "rotate left" button in KParts. + - Use Exiv2 instead of libexif to fix troubles with some JPEG (Bug 136112). + - Fix crash when using Gwenview KPart in kwebdesktop (Bug 130379). + - Fix content of KPart context menu when viewing remote images. + - Do not let the KPart title get overriden when switching tabs. + - Make context menu behavior coherent with KDE (Bug 136449). + - Fix compilation with --enable-final (Bug 134919). + - Do not loose selection when switching from detail to thumbnail view + (Bug 126218). + - In KPart, do not loose selection when starting a drag. + - Fixed behavior of the middle-mouse button (Bug 134590). + - Unless the user rotated the image, saving from the KPart now does a copy of + the image instead of recompressing it. This ensures the KPart won't fail to + save certain files (Bug 131833). + +2006.09.16 - v1.4.0 +- Fixes: + - In a slideshow, let videos play to the end before showing next image/video. + For now it only works with Avi and Ogg videos, not with Mpeg or Quicktime + videos. + +2006.07.19 - v1.3.93 +- New features: + - Use the same delete dialog as Amarok and Juk, to easily choose between + sending files to trash or permanently deleting them. + - It's now possible to define whether Gwenview should remember the last url + and the filter state when it is restarted (Bug 126475). +- Fixes: + - The thumbnail files are now generated using correct name and permissions + according to Thumbnail Managing Standard + (http://jens.triq.net/thumbnail-spec/index.html) (Bug 130937). + - In fullscreen mode, a "Location:" text would sometimes appear above the + fullscreen toolbar. + - Sometimes the Orientation tag was not reset after rotating JPEG images. + +2006.07.14 - v1.3.92b +- Fixes: + - Fix build error (if you got errors about doublespinbox.h, this is it). + +2006.07.14 - v1.3.92 +- New features: + - When available, Gwenview now uses the shooting date instead of the file date + (Bug 98740). + - An entry to start the slide show has been added to the image popup menu (Bug + 130407). + - In the rename dialogs, the file extension is no longer selected by + default (Bug 130408) +- Fixes: + - Fixed file renaming, which got broken in 1.3.91. + - Do not reset filters when configuring image list. + - Do not set keyboard focus on the location field on startup. + - In the status bar, show resolution of remote images, but don't show 0x0 for + files whose resolution is unknown. + - Correct of by one error in selection after files have been removed (Bug + 111240). + - List of supported archive formats is no longer hard coded, so you can for + example add support for rar archives by installing kio_rar (Bug 120974). + - Some focus bugs have been fixed (Bugs 102852 and 130143). + - Do not apply lossless rotations until actual saving, this speeds up + rotations (Bug 130146). + - Reduced the width of the filter bar. + +2006.06.24 - v1.3.91 +- New features: + - Gwenview can now play videos and display SVG files. + - It's now possible to create symbolic links from the main menu and from the + image contextual menu. + (Patch by Steffen Schoenwiese) + - Zoom has been improved: you can now zoom to to width or height, and a zoom + combobox has been added to the application and KPart toolbars. + - Read support for X cursors has been added. + - The slideshow now starts directly. Slideshow options like timing or + fullscreen can be set from the configuration dialog. + (Patch by Martin Filser) + - The slideshow now waits for the next image to be fully prefetched before + advancing. + - The main toolbar is much lighter now that the image specific buttons have + been moved to an image view toolbar. + - The file view from the folder KPart now features the same toolbar as in the + application. + - The file view toolbar can now show a filter bar to filter images by name + and/or date. + - The folder view has been reworked (this may not be definitive). +- Fixes: + - Significantly improved redrawing speed for very large images. + - Fix MMX configure check with GCC 4.x. + - Removed internal libexif. + - Make sure Gwenview libs do not require an executable stack. + (Patch by Christopher Martin) + - Fix a bug which could lead to truncated images when saving to non-local + URLs. + - Only load KIPI plugins when the "Plugins" menu is opened, for faster startup + time and less memory usage. + - Added a confirmation dialog for the window reset menu and renamed the "File + Info" window to "Image Comment" (Bug 116791). + - Simplified configuration of OSD. + - The shadow around the thumbnails has been replaced with a light thin border. + - The history of the url bar is now remembered among sessions. + - In the print dialog, make it possible to enter rational values for width and + height. + - In the save dialog, always set a filename, even for remote urls (Bug 102008). + - In the image KPart, do not switch to another KPart when using the previous + and next buttons. + - In the image and folder KParts, make sure the context menu is adapted to the + mimetype. + - The folder KPart remembers the width of the file view and uses the same + configuration as the application (Bug 83343). + - In the folder KPart, the "trash/remove" context menu entry has been fixed. + +2005.09.11 - v1.3.0 +- Fixes: + - Keyboard shortcuts for file operations now work even if no image is selected. + - Pressing Enter to enter a folder works again. + - On the image view, the "hand" cursors have been replaced with standard + cursors. + - The click/double-click behaviour of the bookmark view has been changed to + match the behaviour of the folder view. + - Icons of the folder KPart have been enhanced. + - Authentication dialogs should now always appear over the main window. + - Folders are no longer included in the image list of KIPI albums. + - A crash which could happen when loading indexed XCF files produced by + recent versions of GIMP has been fixed. + - A bug introduced in the previous version which caused EXIF information to be + removed after editing a comment has been fixed. + - The external tool dialog has been made a bit easier to use by disabling the + detail widgets when no tool is selected. + - Avoid rare cases of the image KPart getting stuck. + - By popular demand (*): double clicking on a thumbnail or the image view now + toggles fullscreen instead of browse mode. + * http://gwenview.sourceforge.net/node/132 + +2005.08.21 - v1.2.92 +- New features: + - The slide show can now display images in random order. + - New shortcuts have been introduced to browse the folder hierarchy: + - Alt+Down goes to the first sub-folder + - Alt+Backspace goes to the previous folder + - Alt+Space goes to the next folder + (Patch by Michael Rolf) + - It is now possible to scroll images with the keyboard. + (Patch by Michael Rolf) + - A new view has been added to quickly access bookmarks. + - Images are now prefetched in advance also when browsing in the thumbnail + view using the cursor keys or keys for next/previous. + - In full screen mode, pressing Enter will toggle the full screen bar. + - KIPI plugins can now access JPEG comments. + - Zoom in and out actions have been added to the KParts. + - An "Other..." entry has been added to the external tools menu. + - The drag'n'drop popup menu now contains an entry to create a symbolic link. +- Fixes: + - In the thumbnail view, folder and archive filenames are always shown, even + if the user choose to hide image filenames. + - When right clicking on files from the folder KPart, the Konqueror popup + menu will now appear, instead of Gwenview's menu. + - The context menu which appears when right clicking on the background of a + file view now shows information relative to the current folder, rather than + the current image. + - The destination URL is now set to the current URL in KIPI plugins. + - The folder name is used as the album name for KIPI plugins. + - The JPEG comment editor has been fixed to avoid adding a dummy character at + the end. + - Double click behaviour has been changed to always toggle browse mode. + +2005.07.17 - v1.2.91 +- New features: + - The file view now features three modes: details, thumbnail with info on the + right and thumbnail with info on bottom. In the "info on the right" + mode, the file name, date, image size and file size are displayed. + In the "info on bottom" mode, the user can choose what information should be + displayed. + - The thumbnail size can now be set with a slider. + - Thumbnail can now be as big as 256x256. + - Non-blocking image preloading in advance. + - With two-pass painting, turn off dithering in the first pass for a small + performance improvement with non-truecolor displays. + - Hints for mouse usage in the image view are shown in the status bar. + - In addition to the file count, the status bar now shows the current image + position. + - Two variables have been introduced for the On Screen Display: %n is the + current image position, %N is the image count. + - An option has been added to disable automatic rotation of images. +- Fixes: + - Progressive JPEG files are really shown progressively. + - In the thumbnail view, make sure we report image sizes for JPEG with + embedded thumbnails. + - The JPEG loader has been fixed so that it doesn't crash on some broken + JPEGs. + - Fix premature end when decoding MNG images. + - Gwenview now dynamically links with installed version of libexif by default. + The included libexif copy is only used if libexif is not installed. Using it + is considered deprecated. + - The "best" smoothing algorithm has been tweaked to produce slightly less + blurry results. + - External tools are now sorted by name in the menu and the dialog. + +2005.04.03 - v1.2.0 +- Fixes: + - A crash which could happen when pressing the 'back' button has been fixed. + +2005.03.19 - v1.2.0pre4 +- New features: + - An item to open the "external tools" dialog has been added at the end of the + "external tools" menu. +- Fixes: + - The layout of the "external tools" dialog has been reworked. + - The image was not correctly displayed after a manual rotation. + - When saving a file, its permissions are kept if it exists or set using umask + if not. + - The history and the back/forward/up buttons in the directory KPart has been + fixed. + +2005.02.27 - v1.2.0pre3 +- Fixes: + - Support for smb:/ and digikamtags:/ ioslaves has been fixed. + - The documentation now appears in KHelpCenter tree. + - When starting a slideshow from a picture in the middle of the list, Gwenview + now loops once to show all images before the start picture, even if the + "Loop" option is not activated. + - The On Screen Display totally hides itself after a while. + +2005.02.13 - v1.2.0pre2 +- New features: + - A documentation has been written. +- Fixes: + - Mouse wheel zooming is now consistent with other KDE applications. + - Show rotation and mirroring buttons on main toolbar. + - Moved all navigation buttons (back, forward, up and home) to the location + toolbar. + - Items in the "Windows" menu are now disabled when Gwenview is in View mode. + - The slideshow has been reworked: it now starts from the current picture and + correctly handles manual image browsing. + +2005.01.23 - v1.2.0pre1 +- Fixes: + - Zoom step halved (100%->150%->200%). + - No image quality loss when printing large images. + - More explicit messages when an error occurs while saving. + +2005.01.08 - v1.1.8 +- New features: + - Zoom actions added to both KPart's. + - Support for animated pictures. + - Fast image scaling function from Imlib2/Mosfet (select 'fast' smoothing + in the configuration dialog). + - Added an item in the "Windows" menu to reset the window layout to the default + configuration. +- Fixes: + - "Lock zoom"/"Auto zoom" options fixed + - Fixed "Clear location"/"Location" shortcuts. + - Make it impossible to undock the file view. It should be easier for new + users to use it this way. + - Fixed crash which could occur when copying multiple files. + +2004.12.19 - v1.1.7 +- New features: + - Double clicking the image view toggles the full screen mode (By Daniel + Thaler) + - It's now possible to select which KIPI plugins should be loaded. + - The On Screen Display now contains "Previous", "Next" and "Exit fullscreen" + buttons. These buttons automatically hide when the cursor hides + itself. + - Adjust brightness, contrast and gamma. + - Going to next/previous image in the image KPart. +- Fixes: + - If the URL given as an argument is a directory, start in browse mode, + not in view mode. + - On Screen Display is back, it was broken in 1.1.6. + - Updated man page. + - KIPI Batch image processing tools now work again. + - Fixed a few bugs in image saving. + - Made the save error messages more explicit. + - Removed the "show toolbar/menubar/statusbar in fullscreen" options. + - When selecting multiple images with Ctrl or Shift, block the "double click + an image goes to fullscreen" feature. + - Removed the "Auto load image" option, it's useless since Gwenview does not + block anymore when loading images. + - Fix reloading in the image KPart. + +2004.10.24 - v1.1.6 +- New features: + - The application now has two modes: browse and view. Browse mode shows all + views: folder, file and image. View mode only shows the image. Gwenview + starts in browse mode except if an image URL is given as an argument. You + can switch between modes using the toolbar button, or with the "View/Browse + mode" menu item or with the Ctrl+Return shortcut. + - JPEGTran code has been integrated into Gwenview, there's no need to install + it separately anymore. +- Fixes: + - Update the EXIF thumbnail when rotating a JPEG file. + - In the folder view, folders now open with a single click (By Daniel Thaler). + - Reworked image->widget coordinate conversions in order to avoid subtle + paint errors. + - Remember computed optimal repaint sizes in the config file, so they are + available immediately after next start. + - Remember shown URL after session restore. + +2004.09.19 - v1.1.5 +- New features: + - The thumbnail progress bar and stop buttons are now embedded in the + thumbnail view. + - The location bar now shows the file names instead of the folders. + - The thumbnails toolbar buttons have been moved to a specialized file view + toolbar. + - It's now possible to assign key shortcuts to KIPI plugins. + - New manpage by Christopher Martin. +- Fixes: + - Do not display the folder name as an image in the status bar. + - Make sure the folder KPart starts in the right folder. + - Unbreak the saving of key shortcuts. + - Remote urls are correctly bookmarked. + - Do not try to overwrite the trash when trashing only one file. + +2004.07.31 - v1.1.4 +- New features: + - In the thumbnail view, It's now possible to sort images in reverse order. + - Use EXIF-stored thumbnail if available. + - Option to disable saving of generated thumbnails to cache. + - In fullscreen mode, it's now possible to display the image comment or size + in addition to the file path. + - The fullscreen On-Screen-Display is more readable now. + - The background color of the image view can be configured. + - When printing, it's now possible to enlarge images so that they fill the + page. +- Fixes: + - In the folder view, pressing Enter now opens the selected folder. + - Use icon list for the configuration dialog. + - Avoid data loss if the JPEG images are saved while being rotated by + JPEGTran. + - The back button in Konqueror now works correctly with gvimagepart. + - The default layout is more user-friendly. + - Non-trivial URLs (e.g. http query URL) are correctly handled. + - You can now drop images on the image view. + +2004.06.11 - v1.1.3 - "Hurry up, I'm getting married tomorrow" +- New features: + - You can now define custom branches in the dir view (By Craig Drummond) + - An image cache has been added to speedup image loading. + - Gwenview now uses freedesktop.org thumbnail spec to store thumbnails. + - A new option to automatically empty thumbnail cache on exit (By Angelo + Naselli). + - The image size is now displayed below file names in thumbnail view. +- Fixes: + - Don't crash when switching to fullscreen while generating thumbnails and + coming back (By Lubos Lunak) + - Faster thumbnail generation (By Lubos Lunak) + - Faster image painting by dynamically determining suitable paint + size (By Lubos Lunak) + - Use the "Standard Background" color as the background for thumbnails and + folders (By Craig Drummond). + - Make sure the current image is reloaded if it has been modified outside + Gwenview. + +2004.05.09 - v1.1.2 +- New features: + - Optional support for KIPI, KDE Image Plugin Interface. + - Incremental downloading of images. + - Image smoothing is much more configurable (By Lubos Lunak). + - KParts will now remember their settings. +- Fixes: + - Fixed several image loading bugs. + - Make sure small and medium size thumbnails do not look jagged. + - Work-around a Qt bug which caused the window title to not come back after + leaving fullscreen mode and reduces flickering (By Lubos Lunak). + - Fixed several bugs in file saving. + - Make sure the loading cursor disappear when the image has finished to load + (By Lubos Lunak). + - Remember last used folder in "copy to" and "move to" dialogs (By Lubos + Lunak). + - Horizontal mouse wheels should work correctly now. + - Entering "~username" in location combo box works now. + - Selecting an URL in the location combo box opens it. + - When viewing an image from within a frame based web site in Konqueror, don't + crash when opening popup menu. + - Give higher priority to the loading of the image than to the generation of + thumbnails (By Lubos Lunak). + +2004.03.20 - v1.1.1 +- New features: + - Added KPart support, this installs in Konqueror a new file view mode and let + you view images in an embedded Gwenview (By Jonathan Riddell). + - Asynchronous JPEG loading, based on Khtml loader. + - Really asynchronous PNG loading (By Lubos Lunak). + - Mouse wheel will now scroll the image by default. Holding Ctrl will scroll + horizontally. An option has been added to the setting dialog to toggle + between scroll and browse (By Jeroen Peters). + - When holding shift over the image, right click will zoom out (By Jeroen + Peters). + - Image painting is now progressive (By Lubos Lunak). +- Fixes: + - The rotate and mirror functions can now work on multiple selection. + - Make it possible to load another image or quit even if you can't save your + changes. + - Gwenview won't spawn multiple instances of jpegtran anymore. + +2004.02.01 - v1.1.0 +- New features: + - New settings in print dialog to specify how the image must be print. + - Big thumbnails are really BIG now :-). + - First implementation of asynchronous image loading. Only for PNG right now. + - Double-clicking an image in the file view will open it in fullscreen [*]. +- Fixes: + - The move and copy dialog now use a tree view. + - In the thumbnail view, create thumbnails for the visible images first + (Thanks to Lubos Lunak). + - Gwenview now uses its own thumbnail cache dir. + - Gave contributors the credit they deserve in the about box [*]. + - Updated to libexif 0.5.12 and applied patches from libexif CVS [*]. + - When going to the parent folder, make sure the folder we were in before is + selected [*]. + - If there's no image in the current folder, select the first visible file [*]. + - When holding down Shift to zoom, keep the same area of the image under the + cursor [*]. + - Nicer drag cursor [*]. + - Hopefully fixed every cases where the image was not centered in the view [*]. +*: Backported to 1.0.1. + +2003.12.07 - v1.0.0 +- New features: + - Show a wait icon for not-generated-yet thumbnails (inspired from Nautilus + thumbnail view). + - Show a broken icon for broken images. +- Fixes: + - If auto-zoom is on, make sure the zoom is updated after rotating an image. + - Fixed crash when loading XCF images if Gwenview was compiled with gcc 3.3.1. + - Before running an external tool, change working directory to current folder. + - When switching images in fullscreen, don't show the cursor. + - Use standard KDE icons for zoom actions. + - New icons for slideshow and image operations. + - New magnifier cursor. + +2003.11.16 - v1.0.0pre4 +- New features: + - Added a new option to hide the busy pointer when loading an image in + fullscreen. + - Added a popup menu to select the sorting mode. Usefull in thumbnail view. +- Fixes: + - Use a KDE dialog for the configuration dialog. + - Removed the image view mouse behavior configuration options. The behavior is + much simpler now: left button to drag image, middle button to toggle + auto-zoom and mouse-wheel to browse images. If you want to zoom hold Shift + and use either the mouse-wheel or the left button. + +2003.11.01 - v1.0.0pre3 +- New features: + - Added a "don't ask me again" check box to the save prompt dialog. + - Added a reload button. + - Added a "Go" button to the location toolbar. +- Fixes: + - Really fixed saving of external tools. + - Make sure the folder view is updated when a folder is renamed. + - The mouse-wheel behaviors are not messed anymore by dialogs or by showing + the popup menu. + +2003.10.11 - v1.0.0pre2 +- New features: + - Added Back/Forward history buttons (based on work from Tudor Calin). + - The parent button can now display a popup menu (by Tudor Calin). + - Simple printing support (by Angelo Naselli). +- Fixes: + - The image comment editor shows more explicit messages when the comment is + empty and when the image can't be commented. + - The external tool dialog won't fail on fresh installation. + - The path to jpegtran is now stored correctly, even if it's not absolute. + - Fixed compilation failure on KDE 3.0. + + +2003.09.27 - v1.0.0pre1 +- New features: + - Toolbars are now configurable and toolbar settings are remembered. + - New dock window to display Meta Info (thanks to Jos van den Oever). + - Cursor over image view changes to reflect the current behavior. + - When toggling autozoom off, restore the previous zoom and position (Based + on a patch by Jos van den Oever). + - It's now possible to define external tools associated with images or + directories. +- Fixes: + - Exiting with Ctrl+Q from the fullscreen won't close the file view for + the next startup. + - Do not switch the file view to detailed mode when leaving the fullscreen + mode. + - Do not stop displaying images when browsing folders containing lots of JPEG + files (more than a thousand). + +2003.06.09 - v0.17.1a +- Fixes: + - Fixed compilation failure on KDE 3.0. + +2003.03.29 - v0.17.1 +- Fixes: + - In the folder view, show the "+" sign in front of folders if they have + sub-folders. + - Lossless manipulations of JPEG images won't remove the EXIF information + anymore. + - Handling of the EXIF orientation tag should now work on KDE 3.0. + - When "auto-zoom" was on, pressing the "reset zoom" button would not + deactivate it. + - Added an "Edit" submenu to the popup menu of the image view, similar to the + main window "Edit" menu. + - Moved "Open with editor" in the "Edit" menu. + - Display the image file name in the window title. + - Fixed the bug which caused the window to grow up when entering folders with + long names (Thanks to Stefan Heinze for the tip). + - Rotating big JPEG images with JPEGTran won't hang anymore. + - Keep the fullscreen button activated to be able to go back to normal mode + when moving to a dir without images in fullscreen mode. + +2003.05.04 - v0.17.0 +- New features: + - Added a cancel button to popup menus, like Konqueror does. + - Added support for dropping files to the file view. +- Fixes: + - Fixed compilation failure on KDE 3.0. + - Clear the image view when the last image of the current folder is removed. + - Hopefully fixed the bug which caused Gwenview to sometimes crash when + invoked with a folder in the command line. + +2003.04.27 - v0.17.0pre3 +- Fixes: + - Really fixed the bug which caused the dock layout to be messed after going + fullscreen. + - Always display the location bar on a new line. + - Fixed the lock which could occur if you kept the go-to-previous or + go-to-next shortcut keys pressed for too long. + +2003.04.26 - v0.17.0pre2 +- New features: + - Support for EXIF orientation information. +- Fixes: + - Don't alter the layout of the docks when toggling dir and file views or + going fullscreen. + - File name won't be cut anymore in the thumbnail view. + - Prompt to save a modified image before quitting. + - Fixed an inconsistency with JPEG lossless rotation. + +2003.04.21 - v0.17.0pre1 +- New features: + - Added bookmarks. + - Show/hide hidden files. + - Image rotation and mirroring (using jpegtran when working on JPEG files to + perform lossless manipulations). + - Image saving. + - You can now smooth scale images. + - New entry in the "View" menu: "Hide Folder And File Views". + - New option to enlarge smaller images when using auto zoom. + - New option to toggle scroll bars on image view. + - New option to select whether deleting files should send them to the trash or + not. +- Fixes: + - Moved the slide show settings to a separate dialog shown before starting it. + - Image count in the status bar doesn't include archives anymore. + - Do not zoom the transparency checkerboard. + +2003.02.13 - v0.16.2 +- Fixes: + - Uses opaque resize for docked views. + - Resizing the window resizes the image view only. + - When using double click mode, double clicking a folder in the icon view + did not open the folder. + +2003.01.31 - v0.16.1 +- Fixes: + - Fixed compilation failure with KDE 3.0 (Thanks to GeniusR13). + +2003.01.30 - v0.16.0 +- New features: + - Support for zip IO slave. + - Added an "erase url" button. +- Fixes: + - Corrected toolbar layout for RTL languages (Thanks to Meni Livne). + - Do not give focus to the address bar on start. + - Do not exit when trying to thumbnailing a broken JPEG (Thanks to Marco + Gazzetta). + - The previous/next shortcuts were wrong in 0.16.0pre1. + +2003.01.12 - v0.16.0pre1 +- New features: + - Support for IO slaves: you can browse FTP files, Windows shares, go into + tarballs... + - Multi-selection support (at last!). + - Added a "home folder" tree branch to the folder view. + - Added a simple slideshow feature. + - Now uses the trash to delete images. + - Added an address bar. + - Displays the filename of the current image in a different (configurable) + color. +- Fixes: + - Do not start dragging folders in the folder view when not necessary. + - When dropping urls and selecting "Move", the drop item will become the + current one only if the item which was the current one was part of the + drop. + +2002.11.05 - v0.15.2 +- Fixes: + - Small jpeg images were getting a stretched thumbnail. + - Fixed the centering of image in scrollable view. + - Enabled the "show folders in file view" by default. + +2002.10.26 - v0.15.1 +- New features: + - Added an item to the popup menus to show the file properties. +- Fixes: + - The selected thumbnail does not look strange anymore when changing the + thumbnail size. + - Always zoom on the center of the image. + - Do not reload the image every time when opening the context menu. + +2002.10.04 - v0.15.0 +- File count was also counting folders. +- Integrated the updated man page by Michael Spanier. +- Selected thumbnail looks nicer now. +- Fixed automatic deselection of the selected thumbnail when using single-click + mode. + +2002.09.14 - v0.15.0pre1 +- New option to prevent Gwenview from loading the first image when it enters a + folder (Thanks to Andreas Pfaller for the patch). +- You can now show the folders in the file view. By enabling this and hiding + the folder view, Gwenview won't have to open all parent folders on startup. +- XCF file format support, thanks to the QXCFI library by Lignum Computing + (http://lignumcomputing.com). +- Thumbnail generator now always saves the thumbnail at the biggest size : + for smaller sizes the big thumbnail is loaded and scaled. This uses less disk + space and make thumbnail size switching faster. +- Reworked the zoom behavior so that it works like the zoom tool in the GIMP. + +2002.08.11 - v0.14.5 +- Fixed the horizontal one pixel lines which appeared in fullscreen mode when + the toolbar was hidden. +- New command line option (-f) to start in fullscreen mode. + +2002.07.28 - v0.14.4 +- Updated thumbnail generation to store thumbnails in the same folder + Konqueror 3 uses (Thanks to Andreas Pfaller and Renchi Raju for the patches). +- Fixed a crash on exit under certain circumstances. +- Should not crash anymore when loading big images. + +2002.07.15 - v0.14.3 +- Really fixed the bug which caused Gwenview to not display image file given as + an argument. +- Fixed ugly look of file names in thumbnail view when word wrap was enabled. +- Fixed flickering and drawing artefacts remaining after zooming in and out. +- Lock zoom state was not properly remembered. +- Updated polish translation. +- Updated german translation. + +2002.07.10 - v0.14.2 +- Fixed a crash if a directory contained URL-like encoded characters (Thanks to + Dario Abatianni for the bug report) +- Do not reload all thumbnails if an image is removed. +- When starting Gwenview with an image file as an argument, the image does + not hide anymore. +- Gwenview won't crash anymore if started with a file that doesn't exist as an + argument. + +2002.06.17 - v0.14.1 +- Fixed a bug in recognition of progressive jpeg images. +- Updated swedish translation by Anders Lindn. +- Added a japanese translation by Ryota Simamoto. + +2002.06.15 - v0.14.0 +- Ported to KDE3 +- Gwenview uses KImageIO for file formats, bringing a few other file formats + such as ico, eps or g3. +- Replaced my own dir widget with the new KDirView widget provided by KDE3. + +2002.05.04 - v0.13.0 +- Thumbnail selection buttons are always activated. +- You can now choose between 'auto-zoom' or 'scroll-and-zoom' in fullscreen + mode. +- You can now lock the zoom to keep the same zoom value during browsing. +- Integrated a patch from Frank Becker to speed up JPEG thumbnail generation. +- Swedish translation. +- More personalizable wheel behavior. +- Gwenview now remembers the 'auto-zoom' state. +- You can now define what interface elements you want to hide in fullscreen + mode. +- Fixed a bug in cache cleaning if the cache was already empty. + + +2002.03.04 - v0.12.0 +- Navigation buttons are now enabled or disabled according to the + position of the file in the folder. +- New zoom option : fit to window. +- Zoom actions are disabled when there's no image. +- No more ugly thumbnails when selected. +- Images are now centered in main view. +- Added popup menus to the file and image views. +- Thumbnails aren't reloaded anymore when deleting a file. +- Added support for external editor. + + +2001.12.30 - v0.11.1 +- Added TIFF support. +- Added drag'n drop support to folder view. +- Bug fix when renaming folder containing folders. + + +2001.12.15 - v0.11.0 +- Korean translation. +- New folder view : more responsive, get automatically updated on + changes, features a popup menu. +- Scrollbars are now reset on image change. +- Should now installs itself in /Graphics rather than in + /Multimedia/Graphics. +- New buttons in config dialog to get the cache size and to empty it. +- Added a man page by Michael Spanier. + + +2001.10.11 - v0.10.1 +- Dutch translation. +- Hungarian translation. +- Now uses Konqueror central thumbnail cache folder. + + +2001.09.29 - v0.10.0 +- Italian translation. +- Polish translation. +- Redesigned the configuration dialog with Qt-Designer, now features + GUI for Avinash Chopde's patch. +- Added a file/open menu item. +- Added an option to hide file names in fullscreen mode. +- Gwenview now displays an error message when it can't load an image. + + +2001.09.01 - v0.9.2 +- German translation. +- Fixed a bug which caused the fullscreen view to be updated even after + coming back to normal. +- Merged a patch from Avinash Chopde to provide default folders for file + copy/move and bypass file operation confirmations (No GUI yet). + + +2001.08.29 - v0.9.1 +- Spanish translation. +- Fixed bad encoding in French translation (no more '?' instead of accent). +- Dock icons were too big. Fixed. + + +2001.08.20 - v0.9.0 +- Added support for alpha channel. +- Gwenview now displays the image size in status bar. +- Fixed wrong icon size for folders on some distributions (my mistake). + + +2001.07.30 - v0.8.0 +- Replaced thumbnail generation with Konqueror code : don't freeze the + interface anymore and cache generated thumbnails on disk. +- You can now select the size of the thumbnails from the menu/toolbar. + + +2001.07.11 - v0.7.0 +- Added zoom in and out feature. +- Thumbnail generation is now non-blocking. +- Uses KIO for file operations. +- Added "move" to file operations. +- Selecting a folder which does not contain images will now empty the image + widget. +- Added a status bar displaying folder and file information. +- Opera-like previous-next mouse navigation. +- Scroll the image by dragging it. +- Fixed a bug which could prevent the toolbar from showing on the first launch. + + +2001.05.23 - v0.6.1 +- Fixed a bug in file view that might not display files. +- Added a Norwegian translation, thanks to Rune Nordvik. + + +2001.05.16 - v0.6.0 +- Full screen support with keyboard, mouse button and mouse wheel navigation. +- Added a toolbar. +- Folder view uses standard folder icons. +- Integration with Konqueror : right click on any folder and select "Browse + with Gwenview". + + +2001.04.10 - v0.5.1 +- Fixed drag'n'drop for file detail view. + + +2001.03.31 - v0.5.0 +- File view items can now be dragged to any KDE application (for example Konqueror). +- French translation. +- File copy dialog opens in current folder. +- Fixed a bug on file copy cancel. +- Fixed a crash on file deletion. +- Shortcut keys are now configurable. +- When using thumbnail view, files are all shown before thumbnail generation begins. +- Added a configuration dialog. + + +2001.03.09 - v0.4.1 +- Fixed crash on file manipulation using thumbnail view. +- Added a progress gauge for thumbnail generation. + + +2001.02.26 - v0.4.0 +- File list use a standard KDE detail view. +- Added a configurable memory cache to speed up image loading. + + +2001.01.28 - v0.3.0 +- Nicer window menu. +- Removed FilePath module : use QT instead. +- Some code cleaning. +- New shortcut for first/previous/next/last image. +- Icon for folders. +- Removed folder column header. +- Thumbnail view. + + +2001.01.16 - v0.2.2 +- Added a window menu to toggle visibility of windows. +- Changed the default button in delete dialog to "Yes". + + +2001.01.15 - v0.2.1 +- Updated mail address and web site. + + +2001.01.08 - v0.2.0 +- Uses docked windows. +- Remember window sizes and configurations. +- Added Help menu with about dialog. +- Uses the KDE way to handle command line parameters. +- Added ability to copy a file. + + +2000.12.10 - v0.1.0 +- Initial release. + diff --git a/README b/README new file mode 100644 index 0000000..0f61168 --- /dev/null +++ b/README @@ -0,0 +1,85 @@ +Gwenview - http://gwenview.sourceforge.net + + + +-> What is it ? + +Gwenview is a simple image viewer for KDE. It features a folder tree window +and a file list window to provide easy navigation in your file hierarchy. +Image loading is done by Qt library, so it supports all image formats your +Qt installation supports. + + +-> Requirements + +KDE 3.1 or more. + + +-> Installation + + ./configure + make + make install + +If configure fails to find your Qt or KDE libs, you will have to type + 'export KDEDIR=/path/to/kde' +and + 'export QTDIR=/path/to/Qt/lib' + + +-> Uninstallation + + make uninstall + + +-> Tips concerning docked windows + +Docked windows are great, but they take a little time to get +accustomed to. Here comes a few tips that you might find handy. + +- While dragging a window, press Esc to cancel the drag. + +- After undocking a window, if you want to dock it back, don't drag it +with the title bar, it won't dock. Drag the little horizontal grip +below the title bar instead. You may also click on the small arrow in +the top right corner, this will get it back to its previous docked place. + +- If you closed a window you can get it back using the "Window" menu. + +- To dock window A on an edge of window B, drag the grip of A to the wanted +edge. To make A and B use tabs, drag the grip of A on the center of B. + + +-> Mouse operations + +You can browse through your image using the Opera-like previous-next mouse +navigation: Keep the left mouse button down and click on the right button to +go to the next image. Keep the right mouse button down and click on the left +button to go to the previous one. +Thanks to Michael Spanier for sending me a patch which started this new feature. + +You can also scroll your image by holding the left mouse button down and +moving the mouse around. + +Middle mouse will toggle the auto zoom on and off. + +By default, the mouse wheel will either scroll the image vertically or go to +previous/next image. This can be configured in the configure dialog. + +Use Shift + mouse wheel to zoom in and out. + +Use Ctrl + mouse wheel to scroll the image horizontally. + + +-> Contact + +mailto:aurelien.gateau@free.fr http://gwenview.sourceforge.net + +You can also join the mailing list: +http://lists.sourceforge.net/lists/listinfo/gwenview-general + + +-> Copyright + +Gwenview is GPL. See the COPYING file for more information. + diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..660b345 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,12406 @@ +## -*- autoconf -*- + +dnl This file is part of the KDE libraries/packages +dnl Copyright (C) 1997 Janos Farkas (chexum@shadow.banki.hu) +dnl (C) 1997,98,99 Stephan Kulow (coolo@kde.org) + +dnl This file is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Library General Public +dnl License as published by the Free Software Foundation; either +dnl version 2 of the License, or (at your option) any later version. + +dnl This library 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 GNU +dnl Library General Public License for more details. + +dnl You should have received a copy of the GNU Library General Public License +dnl along with this library; see the file COPYING.LIB. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +dnl Boston, MA 02110-1301, USA. + +dnl IMPORTANT NOTE: +dnl Please do not modify this file unless you expect your modifications to be +dnl carried into every other module in the repository. +dnl +dnl Single-module modifications are best placed in configure.in for kdelibs +dnl and kdebase or configure.in.in if present. + +# KDE_PATH_X_DIRECT +dnl Internal subroutine of AC_PATH_X. +dnl Set ac_x_includes and/or ac_x_libraries. +AC_DEFUN([KDE_PATH_X_DIRECT], +[ +AC_REQUIRE([KDE_CHECK_LIB64]) + +if test "$ac_x_includes" = NO; then + # Guess where to find include files, by looking for this one X11 .h file. + test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h + + # First, try using that file with no special directory specified. +AC_TRY_CPP([#include <$x_direct_test_include>], +[# We can compile using X headers with no special include directory. +ac_x_includes=], +[# Look for the header file in a standard set of common directories. +# Check X11 before X11Rn because it is often a symlink to the current release. + for ac_dir in \ + /usr/X11/include \ + /usr/X11R6/include \ + /usr/X11R5/include \ + /usr/X11R4/include \ + \ + /usr/include/X11 \ + /usr/include/X11R6 \ + /usr/include/X11R5 \ + /usr/include/X11R4 \ + \ + /usr/local/X11/include \ + /usr/local/X11R6/include \ + /usr/local/X11R5/include \ + /usr/local/X11R4/include \ + \ + /usr/local/include/X11 \ + /usr/local/include/X11R6 \ + /usr/local/include/X11R5 \ + /usr/local/include/X11R4 \ + \ + /usr/X386/include \ + /usr/x386/include \ + /usr/XFree86/include/X11 \ + \ + /usr/include \ + /usr/local/include \ + /usr/unsupported/include \ + /usr/athena/include \ + /usr/local/x11r5/include \ + /usr/lpp/Xamples/include \ + \ + /usr/openwin/include \ + /usr/openwin/share/include \ + ; \ + do + if test -r "$ac_dir/$x_direct_test_include"; then + ac_x_includes=$ac_dir + break + fi + done]) +fi # $ac_x_includes = NO + +if test "$ac_x_libraries" = NO; then + # Check for the libraries. + + test -z "$x_direct_test_library" && x_direct_test_library=Xt + test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc + + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS="$LIBS" + LIBS="-l$x_direct_test_library $LIBS" +AC_TRY_LINK([#include ], [${x_direct_test_function}(1)], +[LIBS="$ac_save_LIBS" +# We can link X programs with no special library path. +ac_x_libraries=], +[LIBS="$ac_save_LIBS" +# First see if replacing the include by lib works. +# Check X11 before X11Rn because it is often a symlink to the current release. +for ac_dir in `echo "$ac_x_includes" | sed s/include/lib${kdelibsuff}/` \ + /usr/X11/lib${kdelibsuff} \ + /usr/X11R6/lib${kdelibsuff} \ + /usr/X11R5/lib${kdelibsuff} \ + /usr/X11R4/lib${kdelibsuff} \ + \ + /usr/lib${kdelibsuff}/X11 \ + /usr/lib${kdelibsuff}/X11R6 \ + /usr/lib${kdelibsuff}/X11R5 \ + /usr/lib${kdelibsuff}/X11R4 \ + \ + /usr/local/X11/lib${kdelibsuff} \ + /usr/local/X11R6/lib${kdelibsuff} \ + /usr/local/X11R5/lib${kdelibsuff} \ + /usr/local/X11R4/lib${kdelibsuff} \ + \ + /usr/local/lib${kdelibsuff}/X11 \ + /usr/local/lib${kdelibsuff}/X11R6 \ + /usr/local/lib${kdelibsuff}/X11R5 \ + /usr/local/lib${kdelibsuff}/X11R4 \ + \ + /usr/X386/lib${kdelibsuff} \ + /usr/x386/lib${kdelibsuff} \ + /usr/XFree86/lib${kdelibsuff}/X11 \ + \ + /usr/lib${kdelibsuff} \ + /usr/local/lib${kdelibsuff} \ + /usr/unsupported/lib${kdelibsuff} \ + /usr/athena/lib${kdelibsuff} \ + /usr/local/x11r5/lib${kdelibsuff} \ + /usr/lpp/Xamples/lib${kdelibsuff} \ + /lib/usr/lib${kdelibsuff}/X11 \ + \ + /usr/openwin/lib${kdelibsuff} \ + /usr/openwin/share/lib${kdelibsuff} \ + ; \ +do +dnl Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl; do + if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done]) +fi # $ac_x_libraries = NO +]) + + +dnl ------------------------------------------------------------------------ +dnl Find a file (or one of more files in a list of dirs) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_FIND_FILE], +[ +$3=NO +for i in $2; +do + for j in $1; + do + echo "configure: __oline__: $i/$j" >&AC_FD_CC + if test -r "$i/$j"; then + echo "taking that" >&AC_FD_CC + $3=$i + break 2 + fi + done +done +]) + +dnl KDE_FIND_PATH(program-name, variable-name, list-of-dirs, +dnl if-not-found, test-parameter, prepend-path) +dnl +dnl Look for program-name in list-of-dirs+$PATH. +dnl If prepend-path is set, look in $PATH+list-of-dirs instead. +dnl If found, $variable-name is set. If not, if-not-found is evaluated. +dnl test-parameter: if set, the program is executed with this arg, +dnl and only a successful exit code is required. +AC_DEFUN([KDE_FIND_PATH], +[ + AC_MSG_CHECKING([for $1]) + if test -n "$$2"; then + kde_cv_path="$$2"; + else + kde_cache=`echo $1 | sed 'y%./+-%__p_%'` + + AC_CACHE_VAL(kde_cv_path_$kde_cache, + [ + kde_cv_path="NONE" + kde_save_IFS=$IFS + IFS=':' + dirs="" + for dir in $PATH; do + dirs="$dirs $dir" + done + if test -z "$6"; then dnl Append dirs in PATH (default) + dirs="$3 $dirs" + else dnl Prepend dirs in PATH (if 6th arg is set) + dirs="$dirs $3" + fi + IFS=$kde_save_IFS + + for dir in $dirs; do + if test -x "$dir/$1"; then + if test -n "$5" + then + evalstr="$dir/$1 $5 2>&1 " + if eval $evalstr; then + kde_cv_path="$dir/$1" + break + fi + else + kde_cv_path="$dir/$1" + break + fi + fi + done + + eval "kde_cv_path_$kde_cache=$kde_cv_path" + + ]) + + eval "kde_cv_path=\"`echo '$kde_cv_path_'$kde_cache`\"" + + fi + + if test -z "$kde_cv_path" || test "$kde_cv_path" = NONE; then + AC_MSG_RESULT(not found) + $4 + else + AC_MSG_RESULT($kde_cv_path) + $2=$kde_cv_path + + fi +]) + +AC_DEFUN([KDE_MOC_ERROR_MESSAGE], +[ + AC_MSG_ERROR([No Qt meta object compiler (moc) found! +Please check whether you installed Qt correctly. +You need to have a running moc binary. +configure tried to run $ac_cv_path_moc and the test didn't +succeed. If configure shouldn't have tried this one, set +the environment variable MOC to the right one before running +configure. +]) +]) + +AC_DEFUN([KDE_UIC_ERROR_MESSAGE], +[ + AC_MSG_WARN([No Qt ui compiler (uic) found! +Please check whether you installed Qt correctly. +You need to have a running uic binary. +configure tried to run $ac_cv_path_uic and the test didn't +succeed. If configure shouldn't have tried this one, set +the environment variable UIC to the right one before running +configure. +]) +]) + + +AC_DEFUN([KDE_CHECK_UIC_FLAG], +[ + AC_MSG_CHECKING([whether uic supports -$1 ]) + kde_cache=`echo $1 | sed 'y% .=/+-%____p_%'` + AC_CACHE_VAL(kde_cv_prog_uic_$kde_cache, + [ + cat >conftest.ui < +EOT + ac_uic_testrun="$UIC_PATH -$1 $2 conftest.ui >/dev/null" + if AC_TRY_EVAL(ac_uic_testrun); then + eval "kde_cv_prog_uic_$kde_cache=yes" + else + eval "kde_cv_prog_uic_$kde_cache=no" + fi + rm -f conftest* + ]) + + if eval "test \"`echo '$kde_cv_prog_uic_'$kde_cache`\" = yes"; then + AC_MSG_RESULT([yes]) + : + $3 + else + AC_MSG_RESULT([no]) + : + $4 + fi +]) + + +dnl ------------------------------------------------------------------------ +dnl Find the meta object compiler and the ui compiler in the PATH, +dnl in $QTDIR/bin, and some more usual places +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_PATH_QT_MOC_UIC], +[ + AC_REQUIRE([KDE_CHECK_PERL]) + qt_bindirs="" + for dir in $kde_qt_dirs; do + qt_bindirs="$qt_bindirs $dir/bin $dir/src/moc" + done + qt_bindirs="$qt_bindirs /usr/bin /usr/X11R6/bin /usr/local/qt/bin" + if test ! "$ac_qt_bindir" = "NO"; then + qt_bindirs="$ac_qt_bindir $qt_bindirs" + fi + + KDE_FIND_PATH(moc, MOC, [$qt_bindirs], [KDE_MOC_ERROR_MESSAGE]) + if test -z "$UIC_NOT_NEEDED"; then + KDE_FIND_PATH(uic, UIC_PATH, [$qt_bindirs], [UIC_PATH=""]) + if test -z "$UIC_PATH" ; then + KDE_UIC_ERROR_MESSAGE + exit 1 + else + UIC=$UIC_PATH + + if test $kde_qtver = 3; then + KDE_CHECK_UIC_FLAG(L,[/nonexistent],ac_uic_supports_libpath=yes,ac_uic_supports_libpath=no) + KDE_CHECK_UIC_FLAG(nounload,,ac_uic_supports_nounload=yes,ac_uic_supports_nounload=no) + + if test x$ac_uic_supports_libpath = xyes; then + UIC="$UIC -L \$(kde_widgetdir)" + fi + if test x$ac_uic_supports_nounload = xyes; then + UIC="$UIC -nounload" + fi + fi + fi + else + UIC="echo uic not available: " + fi + + AC_SUBST(MOC) + AC_SUBST(UIC) + + UIC_TR="i18n" + if test $kde_qtver = 3; then + UIC_TR="tr2i18n" + fi + + AC_SUBST(UIC_TR) +]) + +AC_DEFUN([KDE_1_CHECK_PATHS], +[ + KDE_1_CHECK_PATH_HEADERS + + KDE_TEST_RPATH= + + if test -n "$USE_RPATH"; then + + if test -n "$kde_libraries"; then + KDE_TEST_RPATH="-R $kde_libraries" + fi + + if test -n "$qt_libraries"; then + KDE_TEST_RPATH="$KDE_TEST_RPATH -R $qt_libraries" + fi + + if test -n "$x_libraries"; then + KDE_TEST_RPATH="$KDE_TEST_RPATH -R $x_libraries" + fi + + KDE_TEST_RPATH="$KDE_TEST_RPATH $KDE_EXTRA_RPATH" + fi + +AC_MSG_CHECKING([for KDE libraries installed]) +ac_link='$LIBTOOL_SHELL --silent --mode=link ${CXX-g++} -o conftest $CXXFLAGS $all_includes $CPPFLAGS $LDFLAGS $all_libraries conftest.$ac_ext $LIBS -lkdecore $LIBQT $KDE_TEST_RPATH 1>&5' + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + AC_MSG_RESULT(yes) +else + AC_MSG_ERROR([your system fails at linking a small KDE application! +Check, if your compiler is installed correctly and if you have used the +same compiler to compile Qt and kdelibs as you did use now. +For more details about this problem, look at the end of config.log.]) +fi + +if eval `KDEDIR= ./conftest 2>&5`; then + kde_result=done +else + kde_result=problems +fi + +KDEDIR= ./conftest 2> /dev/null >&5 # make an echo for config.log +kde_have_all_paths=yes + +KDE_SET_PATHS($kde_result) + +]) + +AC_DEFUN([KDE_SET_PATHS], +[ + kde_cv_all_paths="kde_have_all_paths=\"yes\" \ + kde_htmldir=\"$kde_htmldir\" \ + kde_appsdir=\"$kde_appsdir\" \ + kde_icondir=\"$kde_icondir\" \ + kde_sounddir=\"$kde_sounddir\" \ + kde_datadir=\"$kde_datadir\" \ + kde_locale=\"$kde_locale\" \ + kde_cgidir=\"$kde_cgidir\" \ + kde_confdir=\"$kde_confdir\" \ + kde_kcfgdir=\"$kde_kcfgdir\" \ + kde_mimedir=\"$kde_mimedir\" \ + kde_toolbardir=\"$kde_toolbardir\" \ + kde_wallpaperdir=\"$kde_wallpaperdir\" \ + kde_templatesdir=\"$kde_templatesdir\" \ + kde_bindir=\"$kde_bindir\" \ + kde_servicesdir=\"$kde_servicesdir\" \ + kde_servicetypesdir=\"$kde_servicetypesdir\" \ + kde_moduledir=\"$kde_moduledir\" \ + kde_styledir=\"$kde_styledir\" \ + kde_widgetdir=\"$kde_widgetdir\" \ + xdg_appsdir=\"$xdg_appsdir\" \ + xdg_menudir=\"$xdg_menudir\" \ + xdg_directorydir=\"$xdg_directorydir\" \ + kde_result=$1" +]) + +AC_DEFUN([KDE_SET_DEFAULT_PATHS], +[ +if test "$1" = "default"; then + + if test -z "$kde_htmldir"; then + kde_htmldir='\${datadir}/doc/HTML' + fi + if test -z "$kde_appsdir"; then + kde_appsdir='\${datadir}/applnk' + fi + if test -z "$kde_icondir"; then + kde_icondir='\${datadir}/icons' + fi + if test -z "$kde_sounddir"; then + kde_sounddir='\${datadir}/sounds' + fi + if test -z "$kde_datadir"; then + kde_datadir='\${datadir}/apps' + fi + if test -z "$kde_locale"; then + kde_locale='\${datadir}/locale' + fi + if test -z "$kde_cgidir"; then + kde_cgidir='\${exec_prefix}/cgi-bin' + fi + if test -z "$kde_confdir"; then + kde_confdir='\${datadir}/config' + fi + if test -z "$kde_kcfgdir"; then + kde_kcfgdir='\${datadir}/config.kcfg' + fi + if test -z "$kde_mimedir"; then + kde_mimedir='\${datadir}/mimelnk' + fi + if test -z "$kde_toolbardir"; then + kde_toolbardir='\${datadir}/toolbar' + fi + if test -z "$kde_wallpaperdir"; then + kde_wallpaperdir='\${datadir}/wallpapers' + fi + if test -z "$kde_templatesdir"; then + kde_templatesdir='\${datadir}/templates' + fi + if test -z "$kde_bindir"; then + kde_bindir='\${exec_prefix}/bin' + fi + if test -z "$kde_servicesdir"; then + kde_servicesdir='\${datadir}/services' + fi + if test -z "$kde_servicetypesdir"; then + kde_servicetypesdir='\${datadir}/servicetypes' + fi + if test -z "$kde_moduledir"; then + if test "$kde_qtver" = "2"; then + kde_moduledir='\${libdir}/kde2' + else + kde_moduledir='\${libdir}/kde3' + fi + fi + if test -z "$kde_styledir"; then + kde_styledir='\${libdir}/kde3/plugins/styles' + fi + if test -z "$kde_widgetdir"; then + kde_widgetdir='\${libdir}/kde3/plugins/designer' + fi + if test -z "$xdg_appsdir"; then + xdg_appsdir='\${datadir}/applications/kde' + fi + if test -z "$xdg_menudir"; then + xdg_menudir='\${sysconfdir}/xdg/menus' + fi + if test -z "$xdg_directorydir"; then + xdg_directorydir='\${datadir}/desktop-directories' + fi + + KDE_SET_PATHS(defaults) + +else + + if test $kde_qtver = 1; then + AC_MSG_RESULT([compiling]) + KDE_1_CHECK_PATHS + else + AC_MSG_ERROR([path checking not yet supported for KDE 2]) + fi + +fi +]) + +AC_DEFUN([KDE_CHECK_PATHS_FOR_COMPLETENESS], +[ if test -z "$kde_htmldir" || test -z "$kde_appsdir" || + test -z "$kde_icondir" || test -z "$kde_sounddir" || + test -z "$kde_datadir" || test -z "$kde_locale" || + test -z "$kde_cgidir" || test -z "$kde_confdir" || + test -z "$kde_kcfgdir" || + test -z "$kde_mimedir" || test -z "$kde_toolbardir" || + test -z "$kde_wallpaperdir" || test -z "$kde_templatesdir" || + test -z "$kde_bindir" || test -z "$kde_servicesdir" || + test -z "$kde_servicetypesdir" || test -z "$kde_moduledir" || + test -z "$kde_styledir" || test -z "kde_widgetdir" || + test -z "$xdg_appsdir" || test -z "$xdg_menudir" || test -z "$xdg_directorydir" || + test "x$kde_have_all_paths" != "xyes"; then + kde_have_all_paths=no + fi +]) + +AC_DEFUN([KDE_MISSING_PROG_ERROR], +[ + AC_MSG_ERROR([The important program $1 was not found! +Please check whether you installed KDE correctly. +]) +]) + +AC_DEFUN([KDE_MISSING_ARTS_ERROR], +[ + AC_MSG_ERROR([The important program $1 was not found! +Please check whether you installed aRts correctly or use +--without-arts to compile without aRts support (this will remove functionality). +]) +]) + +AC_DEFUN([KDE_SET_DEFAULT_BINDIRS], +[ + kde_default_bindirs="/usr/bin /usr/local/bin /opt/local/bin /usr/X11R6/bin /opt/kde/bin /opt/kde3/bin /usr/kde/bin /usr/local/kde/bin" + test -n "$KDEDIR" && kde_default_bindirs="$KDEDIR/bin $kde_default_bindirs" + if test -n "$KDEDIRS"; then + kde_save_IFS=$IFS + IFS=: + for dir in $KDEDIRS; do + kde_default_bindirs="$dir/bin $kde_default_bindirs " + done + IFS=$kde_save_IFS + fi +]) + +AC_DEFUN([KDE_SUBST_PROGRAMS], +[ + AC_ARG_WITH(arts, + AC_HELP_STRING([--without-arts],[build without aRts [default=no]]), + [build_arts=$withval], + [build_arts=yes] + ) + AM_CONDITIONAL(include_ARTS, test "$build_arts" '!=' "no") + if test "$build_arts" = "no"; then + AC_DEFINE(WITHOUT_ARTS, 1, [Defined if compiling without arts]) + fi + + KDE_SET_DEFAULT_BINDIRS + kde_default_bindirs="$exec_prefix/bin $prefix/bin $kde_libs_prefix/bin $kde_default_bindirs" + KDE_FIND_PATH(dcopidl, DCOPIDL, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidl)]) + KDE_FIND_PATH(dcopidl2cpp, DCOPIDL2CPP, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidl2cpp)]) + if test "$build_arts" '!=' "no"; then + KDE_FIND_PATH(mcopidl, MCOPIDL, [$kde_default_bindirs], [KDE_MISSING_ARTS_ERROR(mcopidl)]) + KDE_FIND_PATH(artsc-config, ARTSCCONFIG, [$kde_default_bindirs], [KDE_MISSING_ARTS_ERROR(artsc-config)]) + fi + KDE_FIND_PATH(meinproc, MEINPROC, [$kde_default_bindirs]) + + kde32ornewer=1 + kde33ornewer=1 + if test -n "$kde_qtver" && test "$kde_qtver" -lt 3; then + kde32ornewer= + kde33ornewer= + else + if test "$kde_qtver" = "3"; then + if test "$kde_qtsubver" -le 1; then + kde32ornewer= + fi + if test "$kde_qtsubver" -le 2; then + kde33ornewer= + fi + if test "$KDECONFIG" != "compiled"; then + if test `$KDECONFIG --version | grep KDE | sed 's/KDE: \(...\).*/\1/'` = 3.2; then + kde33ornewer= + fi + fi + fi + fi + + if test -n "$kde32ornewer"; then + KDE_FIND_PATH(kconfig_compiler, KCONFIG_COMPILER, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kconfig_compiler)]) + KDE_FIND_PATH(dcopidlng, DCOPIDLNG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidlng)]) + fi + if test -n "$kde33ornewer"; then + KDE_FIND_PATH(makekdewidgets, MAKEKDEWIDGETS, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(makekdewidgets)]) + AC_SUBST(MAKEKDEWIDGETS) + fi + KDE_FIND_PATH(xmllint, XMLLINT, [${prefix}/bin ${exec_prefix}/bin], [XMLLINT=""]) + + if test -n "$MEINPROC" -a "$MEINPROC" != "compiled"; then + kde_sharedirs="/usr/share/kde /usr/local/share /usr/share /opt/kde3/share /opt/kde/share $prefix/share" + test -n "$KDEDIR" && kde_sharedirs="$KDEDIR/share $kde_sharedirs" + AC_FIND_FILE(apps/ksgmltools2/customization/kde-chunk.xsl, $kde_sharedirs, KDE_XSL_STYLESHEET) + if test "$KDE_XSL_STYLESHEET" = "NO"; then + KDE_XSL_STYLESHEET="" + else + KDE_XSL_STYLESHEET="$KDE_XSL_STYLESHEET/apps/ksgmltools2/customization/kde-chunk.xsl" + fi + fi + + DCOP_DEPENDENCIES='$(DCOPIDL)' + if test -n "$kde32ornewer"; then + KCFG_DEPENDENCIES='$(KCONFIG_COMPILER)' + DCOP_DEPENDENCIES='$(DCOPIDL) $(DCOPIDLNG)' + AC_SUBST(KCONFIG_COMPILER) + AC_SUBST(KCFG_DEPENDENCIES) + AC_SUBST(DCOPIDLNG) + fi + AC_SUBST(DCOPIDL) + AC_SUBST(DCOPIDL2CPP) + AC_SUBST(DCOP_DEPENDENCIES) + AC_SUBST(MCOPIDL) + AC_SUBST(ARTSCCONFIG) + AC_SUBST(MEINPROC) + AC_SUBST(KDE_XSL_STYLESHEET) + AC_SUBST(XMLLINT) +])dnl + +AC_DEFUN([AC_CREATE_KFSSTND], +[ +AC_REQUIRE([AC_CHECK_RPATH]) + +AC_MSG_CHECKING([for KDE paths]) +kde_result="" +kde_cached_paths=yes +AC_CACHE_VAL(kde_cv_all_paths, +[ + KDE_SET_DEFAULT_PATHS($1) + kde_cached_paths=no +]) +eval "$kde_cv_all_paths" +KDE_CHECK_PATHS_FOR_COMPLETENESS +if test "$kde_have_all_paths" = "no" && test "$kde_cached_paths" = "yes"; then + # wrong values were cached, may be, we can set better ones + kde_result= + kde_htmldir= kde_appsdir= kde_icondir= kde_sounddir= + kde_datadir= kde_locale= kde_cgidir= kde_confdir= kde_kcfgdir= + kde_mimedir= kde_toolbardir= kde_wallpaperdir= kde_templatesdir= + kde_bindir= kde_servicesdir= kde_servicetypesdir= kde_moduledir= + kde_have_all_paths= + kde_styledir= + kde_widgetdir= + xdg_appsdir = xdg_menudir= xdg_directorydir= + KDE_SET_DEFAULT_PATHS($1) + eval "$kde_cv_all_paths" + KDE_CHECK_PATHS_FOR_COMPLETENESS + kde_result="$kde_result (cache overridden)" +fi +if test "$kde_have_all_paths" = "no"; then + AC_MSG_ERROR([configure could not run a little KDE program to test the environment. +Since it had compiled and linked before, it must be a strange problem on your system. +Look at config.log for details. If you are not able to fix this, look at +http://www.kde.org/faq/installation.html or any www.kde.org mirror. +(If you're using an egcs version on Linux, you may update binutils!) +]) +else + rm -f conftest* + AC_MSG_RESULT($kde_result) +fi + +bindir=$kde_bindir + +KDE_SUBST_PROGRAMS + +]) + +AC_DEFUN([AC_SUBST_KFSSTND], +[ +AC_SUBST(kde_htmldir) +AC_SUBST(kde_appsdir) +AC_SUBST(kde_icondir) +AC_SUBST(kde_sounddir) +AC_SUBST(kde_datadir) +AC_SUBST(kde_locale) +AC_SUBST(kde_confdir) +AC_SUBST(kde_kcfgdir) +AC_SUBST(kde_mimedir) +AC_SUBST(kde_wallpaperdir) +AC_SUBST(kde_bindir) +dnl X Desktop Group standards +AC_SUBST(xdg_appsdir) +AC_SUBST(xdg_menudir) +AC_SUBST(xdg_directorydir) +dnl for KDE 2 +AC_SUBST(kde_templatesdir) +AC_SUBST(kde_servicesdir) +AC_SUBST(kde_servicetypesdir) +AC_SUBST(kde_moduledir) +AC_SUBST(kdeinitdir, '$(kde_moduledir)') +AC_SUBST(kde_styledir) +AC_SUBST(kde_widgetdir) +if test "$kde_qtver" = 1; then + kde_minidir="$kde_icondir/mini" +else +# for KDE 1 - this breaks KDE2 apps using minidir, but +# that's the plan ;-/ + kde_minidir="/dev/null" +fi +dnl AC_SUBST(kde_minidir) +dnl AC_SUBST(kde_cgidir) +dnl AC_SUBST(kde_toolbardir) +]) + +AC_DEFUN([KDE_MISC_TESTS], +[ + dnl Checks for libraries. + AC_CHECK_LIB(util, main, [LIBUTIL="-lutil"]) dnl for *BSD + AC_SUBST(LIBUTIL) + AC_CHECK_LIB(compat, main, [LIBCOMPAT="-lcompat"]) dnl for *BSD + AC_SUBST(LIBCOMPAT) + kde_have_crypt= + AC_CHECK_LIB(crypt, crypt, [LIBCRYPT="-lcrypt"; kde_have_crypt=yes], + AC_CHECK_LIB(c, crypt, [kde_have_crypt=yes], [ + AC_MSG_WARN([you have no crypt in either libcrypt or libc. +You should install libcrypt from another source or configure with PAM +support]) + kde_have_crypt=no + ])) + AC_SUBST(LIBCRYPT) + if test $kde_have_crypt = yes; then + AC_DEFINE_UNQUOTED(HAVE_CRYPT, 1, [Defines if your system has the crypt function]) + fi + AC_CHECK_SOCKLEN_T + AC_CHECK_LIB(dnet, dnet_ntoa, [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"]) + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + AC_CHECK_LIB(dnet_stub, dnet_ntoa, + [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"]) + fi + AC_CHECK_FUNC(inet_ntoa) + if test $ac_cv_func_inet_ntoa = no; then + AC_CHECK_LIB(nsl, inet_ntoa, X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl") + fi + AC_CHECK_FUNC(connect) + if test $ac_cv_func_connect = no; then + AC_CHECK_LIB(socket, connect, X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS", , + $X_EXTRA_LIBS) + fi + + AC_CHECK_FUNC(remove) + if test $ac_cv_func_remove = no; then + AC_CHECK_LIB(posix, remove, X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix") + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + AC_CHECK_FUNC(shmat, , + AC_CHECK_LIB(ipc, shmat, X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc")) + + # more headers that need to be explicitly included on darwin + AC_CHECK_HEADERS(sys/types.h stdint.h) + + # sys/bitypes.h is needed for uint32_t and friends on Tru64 + AC_CHECK_HEADERS(sys/bitypes.h) + + # darwin requires a poll emulation library + AC_CHECK_LIB(poll, poll, LIB_POLL="-lpoll") + + # for some image handling on Mac OS X + AC_CHECK_HEADERS(Carbon/Carbon.h) + + # CoreAudio framework + AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [ + AC_DEFINE(HAVE_COREAUDIO, 1, [Define if you have the CoreAudio API]) + FRAMEWORK_COREAUDIO="-Wl,-framework,CoreAudio" + ]) + + AC_CHECK_RES_INIT + AC_SUBST(LIB_POLL) + AC_SUBST(FRAMEWORK_COREAUDIO) + LIBSOCKET="$X_EXTRA_LIBS" + AC_SUBST(LIBSOCKET) + AC_SUBST(X_EXTRA_LIBS) + AC_CHECK_LIB(ucb, killpg, [LIBUCB="-lucb"]) dnl for Solaris2.4 + AC_SUBST(LIBUCB) + + case $host in dnl this *is* LynxOS specific + *-*-lynxos* ) + AC_MSG_CHECKING([LynxOS header file wrappers]) + [CFLAGS="$CFLAGS -D__NO_INCLUDE_WARN__"] + AC_MSG_RESULT(disabled) + AC_CHECK_LIB(bsd, gethostbyname, [LIBSOCKET="-lbsd"]) dnl for LynxOS + ;; + esac + + KDE_CHECK_TYPES + KDE_CHECK_LIBDL + KDE_CHECK_STRLCPY + KDE_CHECK_PIE_SUPPORT + +# darwin needs this to initialize the environment +AC_CHECK_HEADERS(crt_externs.h) +AC_CHECK_FUNC(_NSGetEnviron, [AC_DEFINE(HAVE_NSGETENVIRON, 1, [Define if your system needs _NSGetEnviron to set up the environment])]) + +AH_VERBATIM(_DARWIN_ENVIRON, +[ +#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +# include +# include +# define environ (*_NSGetEnviron()) +#endif +]) + +AH_VERBATIM(_AIX_STRINGS_H_BZERO, +[ +/* + * AIX defines FD_SET in terms of bzero, but fails to include + * that defines bzero. + */ + +#if defined(_AIX) +#include +#endif +]) + +AC_CHECK_FUNCS([vsnprintf snprintf]) + +AH_VERBATIM(_TRU64,[ +/* + * On HP-UX, the declaration of vsnprintf() is needed every time ! + */ + +#if !defined(HAVE_VSNPRINTF) || defined(hpux) +#if __STDC__ +#include +#include +#else +#include +#endif +#ifdef __cplusplus +extern "C" +#endif +int vsnprintf(char *str, size_t n, char const *fmt, va_list ap); +#ifdef __cplusplus +extern "C" +#endif +int snprintf(char *str, size_t n, char const *fmt, ...); +#endif +]) + +]) + +dnl ------------------------------------------------------------------------ +dnl Find the header files and libraries for X-Windows. Extended the +dnl macro AC_PATH_X +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([K_PATH_X], +[ +AC_REQUIRE([KDE_MISC_TESTS])dnl +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_ARG_ENABLE( + embedded, + AC_HELP_STRING([--enable-embedded],[link to Qt-embedded, don't use X]), + kde_use_qt_emb=$enableval, + kde_use_qt_emb=no +) + +AC_ARG_ENABLE( + qtopia, + AC_HELP_STRING([--enable-qtopia],[link to Qt-embedded, link to the Qtopia Environment]), + kde_use_qt_emb_palm=$enableval, + kde_use_qt_emb_palm=no +) + +AC_ARG_ENABLE( + mac, + AC_HELP_STRING([--enable-mac],[link to Qt/Mac (don't use X)]), + kde_use_qt_mac=$enableval, + kde_use_qt_mac=no +) + +# used to disable x11-specific stuff on special platforms +AM_CONDITIONAL(include_x11, test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no") + +if test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no"; then + +AC_MSG_CHECKING(for X) + +AC_CACHE_VAL(kde_cv_have_x, +[# One or both of the vars are not set, and there is no cached value. +if test "{$x_includes+set}" = set || test "$x_includes" = NONE; then + kde_x_includes=NO +else + kde_x_includes=$x_includes +fi +if test "{$x_libraries+set}" = set || test "$x_libraries" = NONE; then + kde_x_libraries=NO +else + kde_x_libraries=$x_libraries +fi + +# below we use the standard autoconf calls +ac_x_libraries=$kde_x_libraries +ac_x_includes=$kde_x_includes + +KDE_PATH_X_DIRECT +dnl AC_PATH_X_XMKMF picks /usr/lib as the path for the X libraries. +dnl Unfortunately, if compiling with the N32 ABI, this is not the correct +dnl location. The correct location is /usr/lib32 or an undefined value +dnl (the linker is smart enough to pick the correct default library). +dnl Things work just fine if you use just AC_PATH_X_DIRECT. +dnl Solaris has a similar problem. AC_PATH_X_XMKMF forces x_includes to +dnl /usr/openwin/include, which doesn't work. /usr/include does work, so +dnl x_includes should be left alone. +case "$host" in +mips-sgi-irix6*) + ;; +*-*-solaris*) + ;; +*) + _AC_PATH_X_XMKMF + if test -z "$ac_x_includes"; then + ac_x_includes="." + fi + if test -z "$ac_x_libraries"; then + ac_x_libraries="/usr/lib${kdelibsuff}" + fi +esac +#from now on we use our own again + +# when the user already gave --x-includes, we ignore +# what the standard autoconf macros told us. +if test "$kde_x_includes" = NO; then + kde_x_includes=$ac_x_includes +fi + +# for --x-libraries too +if test "$kde_x_libraries" = NO; then + kde_x_libraries=$ac_x_libraries +fi + +if test "$kde_x_includes" = NO; then + AC_MSG_ERROR([Can't find X includes. Please check your installation and add the correct paths!]) +fi + +if test "$kde_x_libraries" = NO; then + AC_MSG_ERROR([Can't find X libraries. Please check your installation and add the correct paths!]) +fi + +# Record where we found X for the cache. +kde_cv_have_x="have_x=yes \ + kde_x_includes=$kde_x_includes kde_x_libraries=$kde_x_libraries" +])dnl + +eval "$kde_cv_have_x" + +if test "$have_x" != yes; then + AC_MSG_RESULT($have_x) + no_x=yes +else + AC_MSG_RESULT([libraries $kde_x_libraries, headers $kde_x_includes]) +fi + +if test -z "$kde_x_includes" || test "x$kde_x_includes" = xNONE; then + X_INCLUDES="" + x_includes="."; dnl better than nothing :- + else + x_includes=$kde_x_includes + X_INCLUDES="-I$x_includes" +fi + +if test -z "$kde_x_libraries" || test "x$kde_x_libraries" = xNONE || test "$kde_x_libraries" = "/usr/lib"; then + X_LDFLAGS="" + x_libraries="/usr/lib"; dnl better than nothing :- + else + x_libraries=$kde_x_libraries + X_LDFLAGS="-L$x_libraries" +fi +all_includes="$X_INCLUDES" +all_libraries="$X_LDFLAGS $LDFLAGS_AS_NEEDED $LDFLAGS_NEW_DTAGS" + +# Check for libraries that X11R6 Xt/Xaw programs need. +ac_save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $X_LDFLAGS" +# SM needs ICE to (dynamically) link under SunOS 4.x (so we have to +# check for ICE first), but we must link in the order -lSM -lICE or +# we get undefined symbols. So assume we have SM if we have ICE. +# These have to be linked with before -lX11, unlike the other +# libraries we check for below, so use a different variable. +# --interran@uluru.Stanford.EDU, kb@cs.umb.edu. +AC_CHECK_LIB(ICE, IceConnectionNumber, + [LIBSM="-lSM -lICE"], , $X_EXTRA_LIBS) +LDFLAGS="$ac_save_LDFLAGS" + +LIB_X11='-lX11 $(LIBSOCKET)' + +AC_MSG_CHECKING(for libXext) +AC_CACHE_VAL(kde_cv_have_libXext, +[ +kde_ldflags_safe="$LDFLAGS" +kde_libs_safe="$LIBS" + +LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS" +LIBS="-lXext -lX11 $LIBSOCKET" + +AC_TRY_LINK([ +#include +#ifdef STDC_HEADERS +# include +#endif +], +[ +printf("hello Xext\n"); +], +kde_cv_have_libXext=yes, +kde_cv_have_libXext=no +) + +LDFLAGS=$kde_ldflags_safe +LIBS=$kde_libs_safe +]) + +AC_MSG_RESULT($kde_cv_have_libXext) + +if test "$kde_cv_have_libXext" = "no"; then + AC_MSG_ERROR([We need a working libXext to proceed. Since configure +can't find it itself, we stop here assuming that make wouldn't find +them either.]) +fi + +LIB_XEXT="-lXext" +QTE_NORTTI="" + +elif test "$kde_use_qt_emb" = "yes"; then + dnl We're using QT Embedded + CPPFLAGS=-DQWS + CXXFLAGS="$CXXFLAGS -fno-rtti" + QTE_NORTTI="-fno-rtti -DQWS" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +elif test "$kde_use_qt_mac" = "yes"; then + dnl We're using QT/Mac (I use QT_MAC so that qglobal.h doesn't *have* to + dnl be included to get the information) --Sam + CXXFLAGS="$CXXFLAGS -DQT_MAC -no-cpp-precomp" + CFLAGS="$CFLAGS -DQT_MAC -no-cpp-precomp" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +fi +AC_SUBST(X_PRE_LIBS) +AC_SUBST(LIB_X11) +AC_SUBST(LIB_XRENDER) +AC_SUBST(LIBSM) +AC_SUBST(X_INCLUDES) +AC_SUBST(X_LDFLAGS) +AC_SUBST(x_includes) +AC_SUBST(x_libraries) +AC_SUBST(QTE_NORTTI) +AC_SUBST(LIB_XEXT) + +]) + +AC_DEFUN([KDE_PRINT_QT_PROGRAM], +[ +AC_REQUIRE([KDE_USE_QT]) +cat > conftest.$ac_ext < +#include +EOF +if test "$kde_qtver" = "2"; then +cat >> conftest.$ac_ext < +#include +#include +EOF + +if test $kde_qtsubver -gt 0; then +cat >> conftest.$ac_ext <> conftest.$ac_ext < +#include +#include +EOF +fi + +echo "#if ! ($kde_qt_verstring)" >> conftest.$ac_ext +cat >> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +fi + +rm -f conftest* +CXXFLAGS="$ac_cxxflags_safe" +LDFLAGS="$ac_ldflags_safe" +LIBS="$ac_libs_safe" + +LD_LIBRARY_PATH="$ac_LD_LIBRARY_PATH_safe" +export LD_LIBRARY_PATH +LIBRARY_PATH="$ac_LIBRARY_PATH" +export LIBRARY_PATH +AC_LANG_RESTORE +]) + +if test "$kde_cv_qt_direct" = "yes"; then + AC_MSG_RESULT(yes) + $1 +else + AC_MSG_RESULT(no) + $2 +fi +]) + +dnl ------------------------------------------------------------------------ +dnl Try to find the Qt headers and libraries. +dnl $(QT_LDFLAGS) will be -Lqtliblocation (if needed) +dnl and $(QT_INCLUDES) will be -Iqthdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_PATH_QT_1_3], +[ +AC_REQUIRE([K_PATH_X]) +AC_REQUIRE([KDE_USE_QT]) +AC_REQUIRE([KDE_CHECK_LIB64]) + +dnl ------------------------------------------------------------------------ +dnl Add configure flag to enable linking to MT version of Qt library. +dnl ------------------------------------------------------------------------ + +AC_ARG_ENABLE( + mt, + AC_HELP_STRING([--disable-mt],[link to non-threaded Qt (deprecated)]), + kde_use_qt_mt=$enableval, + [ + if test $kde_qtver = 3; then + kde_use_qt_mt=yes + else + kde_use_qt_mt=no + fi + ] +) + +USING_QT_MT="" + +dnl ------------------------------------------------------------------------ +dnl If we not get --disable-qt-mt then adjust some vars for the host. +dnl ------------------------------------------------------------------------ + +KDE_MT_LDFLAGS= +KDE_MT_LIBS= +if test "x$kde_use_qt_mt" = "xyes"; then + KDE_CHECK_THREADING + if test "x$kde_use_threading" = "xyes"; then + CPPFLAGS="$USE_THREADS -DQT_THREAD_SUPPORT $CPPFLAGS" + KDE_MT_LDFLAGS="$USE_THREADS" + KDE_MT_LIBS="$LIBPTHREAD" + else + kde_use_qt_mt=no + fi +fi +AC_SUBST(KDE_MT_LDFLAGS) +AC_SUBST(KDE_MT_LIBS) + +kde_qt_was_given=yes + +dnl ------------------------------------------------------------------------ +dnl If we haven't been told how to link to Qt, we work it out for ourselves. +dnl ------------------------------------------------------------------------ +if test -z "$LIBQT_GLOB"; then + if test "x$kde_use_qt_emb" = "xyes"; then + LIBQT_GLOB="libqte.*" + else + LIBQT_GLOB="libqt.*" + fi +fi + +dnl ------------------------------------------------------------ +dnl If we got --enable-embedded then adjust the Qt library name. +dnl ------------------------------------------------------------ +if test "x$kde_use_qt_emb" = "xyes"; then + qtlib="qte" +else + qtlib="qt" +fi + +kde_int_qt="-l$qtlib" + +if test -z "$LIBQPE"; then +dnl ------------------------------------------------------------ +dnl If we got --enable-palmtop then add -lqpe to the link line +dnl ------------------------------------------------------------ + if test "x$kde_use_qt_emb" = "xyes"; then + if test "x$kde_use_qt_emb_palm" = "xyes"; then + LIB_QPE="-lqpe" + else + LIB_QPE="" + fi + else + LIB_QPE="" + fi +fi + +dnl ------------------------------------------------------------------------ +dnl If we got --enable-qt-mt then adjust the Qt library name for the host. +dnl ------------------------------------------------------------------------ + +if test "x$kde_use_qt_mt" = "xyes"; then + LIBQT="-l$qtlib-mt" + kde_int_qt="-l$qtlib-mt" + LIBQT_GLOB="lib$qtlib-mt.*" + USING_QT_MT="using -mt" +else + LIBQT="-l$qtlib" +fi + +if test $kde_qtver != 1; then + + AC_REQUIRE([AC_FIND_PNG]) + AC_REQUIRE([AC_FIND_JPEG]) + LIBQT="$LIBQT $LIBPNG $LIBJPEG" +fi + +if test $kde_qtver = 3; then + AC_REQUIRE([KDE_CHECK_LIBDL]) + LIBQT="$LIBQT $LIBDL" +fi + +AC_MSG_CHECKING([for Qt]) + +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBQT="$LIBQT $X_PRE_LIBS -lXext -lX11 $LIBSM $LIBSOCKET" +fi +ac_qt_includes=NO ac_qt_libraries=NO ac_qt_bindir=NO +qt_libraries="" +qt_includes="" +AC_ARG_WITH(qt-dir, + AC_HELP_STRING([--with-qt-dir=DIR],[where the root of Qt is installed ]), + [ ac_qt_includes="$withval"/include + ac_qt_libraries="$withval"/lib${kdelibsuff} + ac_qt_bindir="$withval"/bin + ]) + +AC_ARG_WITH(qt-includes, + AC_HELP_STRING([--with-qt-includes=DIR],[where the Qt includes are. ]), + [ + ac_qt_includes="$withval" + ]) + +kde_qt_libs_given=no + +AC_ARG_WITH(qt-libraries, + AC_HELP_STRING([--with-qt-libraries=DIR],[where the Qt library is installed.]), + [ ac_qt_libraries="$withval" + kde_qt_libs_given=yes + ]) + +AC_CACHE_VAL(ac_cv_have_qt, +[#try to guess Qt locations + +qt_incdirs="" +for dir in $kde_qt_dirs; do + qt_incdirs="$qt_incdirs $dir/include $dir" +done +qt_incdirs="$QTINC $qt_incdirs /usr/local/qt/include /usr/include/qt /usr/include /usr/X11R6/include/X11/qt /usr/X11R6/include/qt /usr/X11R6/include/qt2 /usr/include/qt3 $x_includes" +if test ! "$ac_qt_includes" = "NO"; then + qt_incdirs="$ac_qt_includes $qt_incdirs" +fi + +if test "$kde_qtver" != "1"; then + kde_qt_header=qstyle.h +else + kde_qt_header=qglobal.h +fi + +AC_FIND_FILE($kde_qt_header, $qt_incdirs, qt_incdir) +ac_qt_includes="$qt_incdir" + +qt_libdirs="" +for dir in $kde_qt_dirs; do + qt_libdirs="$qt_libdirs $dir/lib${kdelibsuff} $dir" +done +qt_libdirs="$QTLIB $qt_libdirs /usr/X11R6/lib /usr/lib /usr/local/qt/lib $x_libraries" +if test ! "$ac_qt_libraries" = "NO"; then + qt_libdir=$ac_qt_libraries +else + qt_libdirs="$ac_qt_libraries $qt_libdirs" + # if the Qt was given, the chance is too big that libqt.* doesn't exist + qt_libdir=NONE + for dir in $qt_libdirs; do + try="ls -1 $dir/${LIBQT_GLOB}" + if test -n "`$try 2> /dev/null`"; then qt_libdir=$dir; break; else echo "tried $dir" >&AC_FD_CC ; fi + done +fi +for a in $qt_libdir/lib`echo ${kde_int_qt} | sed 's,^-l,,'`_incremental.*; do + if test -e "$a"; then + LIBQT="$LIBQT ${kde_int_qt}_incremental" + break + fi +done + +ac_qt_libraries="$qt_libdir" + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + +ac_cxxflags_safe="$CXXFLAGS" +ac_ldflags_safe="$LDFLAGS" +ac_libs_safe="$LIBS" + +CXXFLAGS="$CXXFLAGS -I$qt_incdir $all_includes" +LDFLAGS="$LDFLAGS -L$qt_libdir $all_libraries $USER_LDFLAGS $KDE_MT_LDFLAGS" +LIBS="$LIBS $LIBQT $KDE_MT_LIBS" + +KDE_PRINT_QT_PROGRAM + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + rm -f conftest* +else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC + ac_qt_libraries="NO" +fi +rm -f conftest* +CXXFLAGS="$ac_cxxflags_safe" +LDFLAGS="$ac_ldflags_safe" +LIBS="$ac_libs_safe" + +AC_LANG_RESTORE +if test "$ac_qt_includes" = NO || test "$ac_qt_libraries" = NO; then + ac_cv_have_qt="have_qt=no" + ac_qt_notfound="" + missing_qt_mt="" + if test "$ac_qt_includes" = NO; then + if test "$ac_qt_libraries" = NO; then + ac_qt_notfound="(headers and libraries)"; + else + ac_qt_notfound="(headers)"; + fi + else + if test "x$kde_use_qt_mt" = "xyes"; then + missing_qt_mt=" +Make sure that you have compiled Qt with thread support!" + ac_qt_notfound="(library $qtlib-mt)"; + else + ac_qt_notfound="(library $qtlib)"; + fi + fi + + AC_MSG_ERROR([Qt ($kde_qt_minversion) $ac_qt_notfound not found. Please check your installation! +For more details about this problem, look at the end of config.log.$missing_qt_mt]) +else + have_qt="yes" +fi +]) + +eval "$ac_cv_have_qt" + +if test "$have_qt" != yes; then + AC_MSG_RESULT([$have_qt]); +else + ac_cv_have_qt="have_qt=yes \ + ac_qt_includes=$ac_qt_includes ac_qt_libraries=$ac_qt_libraries" + AC_MSG_RESULT([libraries $ac_qt_libraries, headers $ac_qt_includes $USING_QT_MT]) + + qt_libraries="$ac_qt_libraries" + qt_includes="$ac_qt_includes" +fi + +if test ! "$kde_qt_libs_given" = "yes" && test ! "$kde_qtver" = 3; then + KDE_CHECK_QT_DIRECT(qt_libraries= ,[]) +fi + +AC_SUBST(qt_libraries) +AC_SUBST(qt_includes) + +if test "$qt_includes" = "$x_includes" || test -z "$qt_includes"; then + QT_INCLUDES="" +else + QT_INCLUDES="-I$qt_includes" + all_includes="$QT_INCLUDES $all_includes" +fi + +if test "$qt_libraries" = "$x_libraries" || test -z "$qt_libraries"; then + QT_LDFLAGS="" +else + QT_LDFLAGS="-L$qt_libraries" + all_libraries="$QT_LDFLAGS $all_libraries" +fi +test -z "$KDE_MT_LDFLAGS" || all_libraries="$all_libraries $KDE_MT_LDFLAGS" + +AC_SUBST(QT_INCLUDES) +AC_SUBST(QT_LDFLAGS) +AC_PATH_QT_MOC_UIC + +KDE_CHECK_QT_JPEG + +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIB_QT="$kde_int_qt $LIBJPEG_QT "'$(LIBZ) $(LIBPNG) -lXext $(LIB_X11) $(LIBSM)' +else +LIB_QT="$kde_int_qt $LIBJPEG_QT "'$(LIBZ) $(LIBPNG)' +fi +test -z "$KDE_MT_LIBS" || LIB_QT="$LIB_QT $KDE_MT_LIBS" +for a in $qt_libdir/lib`echo ${kde_int_qt} | sed 's,^-l,,'`_incremental.*; do + if test -e "$a"; then + LIB_QT="$LIB_QT ${kde_int_qt}_incremental" + break + fi +done + +AC_SUBST(LIB_QT) +AC_SUBST(LIB_QPE) + +AC_SUBST(kde_qtver) +]) + +AC_DEFUN([AC_PATH_QT], +[ +AC_PATH_QT_1_3 +]) + +AC_DEFUN([KDE_CHECK_UIC_PLUGINS], +[ +AC_REQUIRE([AC_PATH_QT_MOC_UIC]) + +if test x$ac_uic_supports_libpath = xyes; then + +AC_MSG_CHECKING([if UIC has KDE plugins available]) +AC_CACHE_VAL(kde_cv_uic_plugins, +[ +cat > actest.ui << EOF + +NewConnectionDialog + + + + testInput + + + + +EOF + + + +kde_cv_uic_plugins=no +kde_line="$UIC_PATH -L $kde_widgetdir" +if test x$ac_uic_supports_nounload = xyes; then + kde_line="$kde_line -nounload" +fi +kde_line="$kde_line -impl actest.h actest.ui > actest.cpp" +if AC_TRY_EVAL(kde_line); then + # if you're trying to debug this check and think it's incorrect, + # better check your installation. The check _is_ correct - your + # installation is not. + if test -f actest.cpp && grep klineedit actest.cpp > /dev/null; then + kde_cv_uic_plugins=yes + fi +fi +rm -f actest.ui actest.cpp +]) + +AC_MSG_RESULT([$kde_cv_uic_plugins]) +if test "$kde_cv_uic_plugins" != yes; then + AC_MSG_ERROR([ +you need to install kdelibs first. + +If you did install kdelibs, then the Qt version that is picked up by +this configure is not the same version you used to compile kdelibs. +The Qt Plugin installed by kdelibs is *ONLY* loadable if it is the +_same Qt version_, compiled with the _same compiler_ and the same Qt +configuration settings. +]) +fi +fi +]) + +AC_DEFUN([KDE_CHECK_FINAL], +[ + AC_ARG_ENABLE(final, + AC_HELP_STRING([--enable-final], + [build size optimized apps (experimental - needs lots of memory)]), + kde_use_final=$enableval, kde_use_final=no) + + if test "x$kde_use_final" = "xyes"; then + KDE_USE_FINAL_TRUE="" + KDE_USE_FINAL_FALSE="#" + else + KDE_USE_FINAL_TRUE="#" + KDE_USE_FINAL_FALSE="" + fi + AC_SUBST(KDE_USE_FINAL_TRUE) + AC_SUBST(KDE_USE_FINAL_FALSE) +]) + +AC_DEFUN([KDE_CHECK_CLOSURE], +[ + AC_ARG_ENABLE(closure, + AC_HELP_STRING([--enable-closure],[delay template instantiation]), + kde_use_closure=$enableval, kde_use_closure=no) + + KDE_NO_UNDEFINED="" + if test "x$kde_use_closure" = "xyes"; then + KDE_USE_CLOSURE_TRUE="" + KDE_USE_CLOSURE_FALSE="#" +# CXXFLAGS="$CXXFLAGS $REPO" + else + KDE_USE_CLOSURE_TRUE="#" + KDE_USE_CLOSURE_FALSE="" + KDE_NO_UNDEFINED="" + fi + AC_SUBST(KDE_USE_CLOSURE_TRUE) + AC_SUBST(KDE_USE_CLOSURE_FALSE) + AC_SUBST(KDE_NO_UNDEFINED) +]) + +dnl Check if the linker supports --enable-new-dtags and --as-needed +AC_DEFUN([KDE_CHECK_NEW_LDFLAGS], +[ + AC_ARG_ENABLE(new_ldflags, + AC_HELP_STRING([--enable-new-ldflags], + [enable the new linker flags]), + kde_use_new_ldflags=$enableval, + kde_use_new_ldflags=no) + + LDFLAGS_AS_NEEDED="" + LDFLAGS_NEW_DTAGS="" + if test "x$kde_use_new_ldflags" = "xyes"; then + LDFLAGS_NEW_DTAGS="" + KDE_CHECK_COMPILER_FLAG([Wl,--enable-new-dtags], + [LDFLAGS_NEW_DTAGS="-Wl,--enable-new-dtags"],) + + KDE_CHECK_COMPILER_FLAG([Wl,--as-needed], + [LDFLAGS_AS_NEEDED="-Wl,--as-needed"],) + fi + AC_SUBST(LDFLAGS_AS_NEEDED) + AC_SUBST(LDFLAGS_NEW_DTAGS) +]) + +AC_DEFUN([KDE_CHECK_NMCHECK], +[ + AC_ARG_ENABLE(nmcheck,AC_HELP_STRING([--enable-nmcheck],[enable automatic namespace cleanness check]), + kde_use_nmcheck=$enableval, kde_use_nmcheck=no) + + if test "$kde_use_nmcheck" = "yes"; then + KDE_USE_NMCHECK_TRUE="" + KDE_USE_NMCHECK_FALSE="#" + else + KDE_USE_NMCHECK_TRUE="#" + KDE_USE_NMCHECK_FALSE="" + fi + AC_SUBST(KDE_USE_NMCHECK_TRUE) + AC_SUBST(KDE_USE_NMCHECK_FALSE) +]) + +AC_DEFUN([KDE_EXPAND_MAKEVAR], [ +savex=$exec_prefix +test "x$exec_prefix" = xNONE && exec_prefix=$prefix +tmp=$$2 +while $1=`eval echo "$tmp"`; test "x$$1" != "x$tmp"; do tmp=$$1; done +exec_prefix=$savex +]) + +dnl ------------------------------------------------------------------------ +dnl Now, the same with KDE +dnl $(KDE_LDFLAGS) will be the kdeliblocation (if needed) +dnl and $(kde_includes) will be the kdehdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_BASE_PATH_KDE], +[ +AC_REQUIRE([KDE_CHECK_STL]) +AC_REQUIRE([AC_PATH_QT])dnl +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_CHECK_RPATH +AC_MSG_CHECKING([for KDE]) + +if test "${prefix}" != NONE; then + kde_includes=${includedir} + KDE_EXPAND_MAKEVAR(ac_kde_includes, includedir) + + kde_libraries=${libdir} + KDE_EXPAND_MAKEVAR(ac_kde_libraries, libdir) + +else + ac_kde_includes= + ac_kde_libraries= + kde_libraries="" + kde_includes="" +fi + +AC_CACHE_VAL(ac_cv_have_kde, +[#try to guess kde locations + +if test "$kde_qtver" = 1; then + kde_check_header="ksock.h" + kde_check_lib="libkdecore.la" +else + kde_check_header="ksharedptr.h" + kde_check_lib="libkio.la" +fi + +if test -z "$1"; then + +kde_incdirs="$kde_libs_prefix/include /usr/lib/kde/include /usr/local/kde/include /usr/local/include /usr/kde/include /usr/include/kde /usr/include /opt/kde3/include /opt/kde/include $x_includes $qt_includes" +test -n "$KDEDIR" && kde_incdirs="$KDEDIR/include $KDEDIR/include/kde $KDEDIR $kde_incdirs" +kde_incdirs="$ac_kde_includes $kde_incdirs" +AC_FIND_FILE($kde_check_header, $kde_incdirs, kde_incdir) +ac_kde_includes="$kde_incdir" + +if test -n "$ac_kde_includes" && test ! -r "$ac_kde_includes/$kde_check_header"; then + AC_MSG_ERROR([ +in the prefix, you've chosen, are no KDE headers installed. This will fail. +So, check this please and use another prefix!]) +fi + +kde_libdirs="$kde_libs_prefix/lib${kdelibsuff} /usr/lib/kde/lib${kdelibsuff} /usr/local/kde/lib${kdelibsuff} /usr/kde/lib${kdelibsuff} /usr/lib${kdelibsuff}/kde /usr/lib${kdelibsuff}/kde3 /usr/lib${kdelibsuff} /usr/X11R6/lib${kdelibsuff} /usr/local/lib${kdelibsuff} /opt/kde3/lib${kdelibsuff} /opt/kde/lib${kdelibsuff} /usr/X11R6/kde/lib${kdelibsuff}" +test -n "$KDEDIR" && kde_libdirs="$KDEDIR/lib${kdelibsuff} $KDEDIR $kde_libdirs" +kde_libdirs="$ac_kde_libraries $libdir $kde_libdirs" +AC_FIND_FILE($kde_check_lib, $kde_libdirs, kde_libdir) +ac_kde_libraries="$kde_libdir" + +kde_widgetdir=NO +dnl this might be somewhere else +AC_FIND_FILE("kde3/plugins/designer/kdewidgets.la", $kde_libdirs, kde_widgetdir) + +if test -n "$ac_kde_libraries" && test ! -r "$ac_kde_libraries/$kde_check_lib"; then +AC_MSG_ERROR([ +in the prefix, you've chosen, are no KDE libraries installed. This will fail. +So, check this please and use another prefix!]) +fi + +if test -n "$kde_widgetdir" && test ! -r "$kde_widgetdir/kde3/plugins/designer/kdewidgets.la"; then +AC_MSG_ERROR([ +I can't find the designer plugins. These are required and should have been installed +by kdelibs]) +fi + +if test -n "$kde_widgetdir"; then + kde_widgetdir="$kde_widgetdir/kde3/plugins/designer" +fi + + +if test "$ac_kde_includes" = NO || test "$ac_kde_libraries" = NO || test "$kde_widgetdir" = NO; then + ac_cv_have_kde="have_kde=no" +else + ac_cv_have_kde="have_kde=yes \ + ac_kde_includes=$ac_kde_includes ac_kde_libraries=$ac_kde_libraries" +fi + +else dnl test -z $1, e.g. from kdelibs + + ac_cv_have_kde="have_kde=no" + +fi +])dnl + +eval "$ac_cv_have_kde" + +if test "$have_kde" != "yes"; then + if test "${prefix}" = NONE; then + ac_kde_prefix="$ac_default_prefix" + else + ac_kde_prefix="$prefix" + fi + if test "$exec_prefix" = NONE; then + ac_kde_exec_prefix="$ac_kde_prefix" + AC_MSG_RESULT([will be installed in $ac_kde_prefix]) + else + ac_kde_exec_prefix="$exec_prefix" + AC_MSG_RESULT([will be installed in $ac_kde_prefix and $ac_kde_exec_prefix]) + fi + + kde_libraries="${libdir}" + kde_includes="${includedir}" + +else + ac_cv_have_kde="have_kde=yes \ + ac_kde_includes=$ac_kde_includes ac_kde_libraries=$ac_kde_libraries" + AC_MSG_RESULT([libraries $ac_kde_libraries, headers $ac_kde_includes]) + + kde_libraries="$ac_kde_libraries" + kde_includes="$ac_kde_includes" +fi +AC_SUBST(kde_libraries) +AC_SUBST(kde_includes) + +if test "$kde_includes" = "$x_includes" || test "$kde_includes" = "$qt_includes" || test "$kde_includes" = "/usr/include"; then + KDE_INCLUDES="" +else + KDE_INCLUDES="-I$kde_includes" + all_includes="$KDE_INCLUDES $all_includes" +fi + +KDE_DEFAULT_CXXFLAGS="-DQT_CLEAN_NAMESPACE -DQT_NO_ASCII_CAST -DQT_NO_STL -DQT_NO_COMPAT -DQT_NO_TRANSLATION" + +KDE_LDFLAGS="-L$kde_libraries" +if test ! "$kde_libraries" = "$x_libraries" && test ! "$kde_libraries" = "$qt_libraries" ; then + all_libraries="$KDE_LDFLAGS $all_libraries" +fi + +AC_SUBST(KDE_LDFLAGS) +AC_SUBST(KDE_INCLUDES) + +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + +all_libraries="$all_libraries $USER_LDFLAGS" +all_includes="$all_includes $USER_INCLUDES" +AC_SUBST(all_includes) +AC_SUBST(all_libraries) + +if test -z "$1"; then +KDE_CHECK_UIC_PLUGINS +fi + +ac_kde_libraries="$kde_libdir" + +AC_SUBST(AUTODIRS) + + +]) + +AC_DEFUN([KDE_CHECK_EXTRA_LIBS], +[ +AC_MSG_CHECKING(for extra includes) +AC_ARG_WITH(extra-includes,AC_HELP_STRING([--with-extra-includes=DIR],[adds non standard include paths]), + kde_use_extra_includes="$withval", + kde_use_extra_includes=NONE +) +kde_extra_includes= +if test -n "$kde_use_extra_includes" && \ + test "$kde_use_extra_includes" != "NONE"; then + + ac_save_ifs=$IFS + IFS=':' + for dir in $kde_use_extra_includes; do + kde_extra_includes="$kde_extra_includes $dir" + USER_INCLUDES="$USER_INCLUDES -I$dir" + done + IFS=$ac_save_ifs + kde_use_extra_includes="added" +else + kde_use_extra_includes="no" +fi +AC_SUBST(USER_INCLUDES) + +AC_MSG_RESULT($kde_use_extra_includes) + +kde_extra_libs= +AC_MSG_CHECKING(for extra libs) +AC_ARG_WITH(extra-libs,AC_HELP_STRING([--with-extra-libs=DIR],[adds non standard library paths]), + kde_use_extra_libs=$withval, + kde_use_extra_libs=NONE +) +if test -n "$kde_use_extra_libs" && \ + test "$kde_use_extra_libs" != "NONE"; then + + ac_save_ifs=$IFS + IFS=':' + for dir in $kde_use_extra_libs; do + kde_extra_libs="$kde_extra_libs $dir" + KDE_EXTRA_RPATH="$KDE_EXTRA_RPATH -R $dir" + USER_LDFLAGS="$USER_LDFLAGS -L$dir" + done + IFS=$ac_save_ifs + kde_use_extra_libs="added" +else + kde_use_extra_libs="no" +fi + +AC_SUBST(USER_LDFLAGS) + +AC_MSG_RESULT($kde_use_extra_libs) + +]) + +AC_DEFUN([KDE_1_CHECK_PATH_HEADERS], +[ + AC_MSG_CHECKING([for KDE headers installed]) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS +cat > conftest.$ac_ext < +#endif +#include +#include "confdefs.h" +#include + +int main() { + printf("kde_htmldir=\\"%s\\"\n", KApplication::kde_htmldir().data()); + printf("kde_appsdir=\\"%s\\"\n", KApplication::kde_appsdir().data()); + printf("kde_icondir=\\"%s\\"\n", KApplication::kde_icondir().data()); + printf("kde_sounddir=\\"%s\\"\n", KApplication::kde_sounddir().data()); + printf("kde_datadir=\\"%s\\"\n", KApplication::kde_datadir().data()); + printf("kde_locale=\\"%s\\"\n", KApplication::kde_localedir().data()); + printf("kde_cgidir=\\"%s\\"\n", KApplication::kde_cgidir().data()); + printf("kde_confdir=\\"%s\\"\n", KApplication::kde_configdir().data()); + printf("kde_mimedir=\\"%s\\"\n", KApplication::kde_mimedir().data()); + printf("kde_toolbardir=\\"%s\\"\n", KApplication::kde_toolbardir().data()); + printf("kde_wallpaperdir=\\"%s\\"\n", + KApplication::kde_wallpaperdir().data()); + printf("kde_bindir=\\"%s\\"\n", KApplication::kde_bindir().data()); + printf("kde_partsdir=\\"%s\\"\n", KApplication::kde_partsdir().data()); + printf("kde_servicesdir=\\"/tmp/dummy\\"\n"); + printf("kde_servicetypesdir=\\"/tmp/dummy\\"\n"); + printf("kde_moduledir=\\"/tmp/dummy\\"\n"); + printf("kde_styledir=\\"/tmp/dummy\\"\n"); + printf("kde_widgetdir=\\"/tmp/dummy\\"\n"); + printf("xdg_appsdir=\\"/tmp/dummy\\"\n"); + printf("xdg_menudir=\\"/tmp/dummy\\"\n"); + printf("xdg_directorydir=\\"/tmp/dummy\\"\n"); + printf("kde_kcfgdir=\\"/tmp/dummy\\"\n"); + return 0; + } +EOF + + ac_save_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$all_includes $CPPFLAGS" + if AC_TRY_EVAL(ac_compile); then + AC_MSG_RESULT(yes) + else + AC_MSG_ERROR([your system is not able to compile a small KDE application! +Check, if you installed the KDE header files correctly. +For more details about this problem, look at the end of config.log.]) + fi + CPPFLAGS=$ac_save_CPPFLAGS + + AC_LANG_RESTORE +]) + +AC_DEFUN([KDE_CHECK_KDEQTADDON], +[ +AC_MSG_CHECKING(for kde-qt-addon) +AC_CACHE_VAL(kde_cv_have_kdeqtaddon, +[ + kde_ldflags_safe="$LDFLAGS" + kde_libs_safe="$LIBS" + kde_cxxflags_safe="$CXXFLAGS" + + LIBS="-lkde-qt-addon $LIBQT $LIBS" + CXXFLAGS="$CXXFLAGS -I$prefix/include -I$prefix/include/kde $all_includes" + LDFLAGS="$LDFLAGS $all_libraries $USER_LDFLAGS" + + AC_TRY_LINK([ + #include + ], + [ + QDomDocument doc; + ], + kde_cv_have_kdeqtaddon=yes, + kde_cv_have_kdeqtaddon=no + ) + + LDFLAGS=$kde_ldflags_safe + LIBS=$kde_libs_safe + CXXFLAGS=$kde_cxxflags_safe +]) + +AC_MSG_RESULT($kde_cv_have_kdeqtaddon) + +if test "$kde_cv_have_kdeqtaddon" = "no"; then + AC_MSG_ERROR([Can't find libkde-qt-addon. You need to install it first. +It is a separate package (and CVS module) named kde-qt-addon.]) +fi +]) + +AC_DEFUN([KDE_CREATE_LIBS_ALIASES], +[ + AC_REQUIRE([KDE_MISC_TESTS]) + AC_REQUIRE([KDE_CHECK_LIBDL]) + AC_REQUIRE([K_PATH_X]) + +if test $kde_qtver = 3; then + case $host in + *cygwin*) lib_kded="-lkdeinit_kded" ;; + *) lib_kded="" ;; + esac + AC_SUBST(LIB_KDED, $lib_kded) + AC_SUBST(LIB_KDECORE, "-lkdecore") + AC_SUBST(LIB_KDEUI, "-lkdeui") + AC_SUBST(LIB_KIO, "-lkio") + AC_SUBST(LIB_KJS, "-lkjs") + AC_SUBST(LIB_SMB, "-lsmb") + AC_SUBST(LIB_KAB, "-lkab") + AC_SUBST(LIB_KABC, "-lkabc") + AC_SUBST(LIB_KHTML, "-lkhtml") + AC_SUBST(LIB_KSPELL, "-lkspell") + AC_SUBST(LIB_KPARTS, "-lkparts") + AC_SUBST(LIB_KDEPRINT, "-lkdeprint") + AC_SUBST(LIB_KUTILS, "-lkutils") + AC_SUBST(LIB_KDEPIM, "-lkdepim") + AC_SUBST(LIB_KIMPROXY, "-lkimproxy") + AC_SUBST(LIB_KNEWSTUFF, "-lknewstuff") + AC_SUBST(LIB_KDNSSD, "-lkdnssd") + AC_SUBST(LIB_KUNITTEST, "-lkunittest") +# these are for backward compatibility + AC_SUBST(LIB_KSYCOCA, "-lkio") + AC_SUBST(LIB_KFILE, "-lkio") +elif test $kde_qtver = 2; then + AC_SUBST(LIB_KDECORE, "-lkdecore") + AC_SUBST(LIB_KDEUI, "-lkdeui") + AC_SUBST(LIB_KIO, "-lkio") + AC_SUBST(LIB_KSYCOCA, "-lksycoca") + AC_SUBST(LIB_SMB, "-lsmb") + AC_SUBST(LIB_KFILE, "-lkfile") + AC_SUBST(LIB_KAB, "-lkab") + AC_SUBST(LIB_KHTML, "-lkhtml") + AC_SUBST(LIB_KSPELL, "-lkspell") + AC_SUBST(LIB_KPARTS, "-lkparts") + AC_SUBST(LIB_KDEPRINT, "-lkdeprint") +else + AC_SUBST(LIB_KDECORE, "-lkdecore -lXext $(LIB_QT)") + AC_SUBST(LIB_KDEUI, "-lkdeui $(LIB_KDECORE)") + AC_SUBST(LIB_KFM, "-lkfm $(LIB_KDECORE)") + AC_SUBST(LIB_KFILE, "-lkfile $(LIB_KFM) $(LIB_KDEUI)") + AC_SUBST(LIB_KAB, "-lkab $(LIB_KIMGIO) $(LIB_KDECORE)") +fi +]) + +AC_DEFUN([AC_PATH_KDE], +[ + AC_BASE_PATH_KDE + AC_ARG_ENABLE(path-check,AC_HELP_STRING([--disable-path-check],[don't try to find out, where to install]), + [ + if test "$enableval" = "no"; + then ac_use_path_checking="default" + else ac_use_path_checking="" + fi + ], + [ + if test "$kde_qtver" = 1; + then ac_use_path_checking="" + else ac_use_path_checking="default" + fi + ] + ) + + AC_CREATE_KFSSTND($ac_use_path_checking) + + AC_SUBST_KFSSTND + KDE_CREATE_LIBS_ALIASES +]) + +dnl KDE_CHECK_FUNC_EXT(, [headers], [sample-use], [C prototype], [autoheader define], [call if found]) +AC_DEFUN([KDE_CHECK_FUNC_EXT], +[ +AC_MSG_CHECKING(for $1) +AC_CACHE_VAL(kde_cv_func_$1, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +save_CXXFLAGS="$CXXFLAGS" +kde_safe_LIBS="$LIBS" +LIBS="$LIBS $X_EXTRA_LIBS" +AC_TRY_COMPILE([ +$2 +], +[ +$3 +], +kde_cv_func_$1=yes, +kde_cv_func_$1=no) +CXXFLAGS="$save_CXXFLAGS" +LIBS="$kde_safe_LIBS" +AC_LANG_RESTORE +]) + +AC_MSG_RESULT($kde_cv_func_$1) + +AC_MSG_CHECKING([if $1 needs custom prototype]) +AC_CACHE_VAL(kde_cv_proto_$1, +[ +if test "x$kde_cv_func_$1" = xyes; then + kde_cv_proto_$1=no +else + case "$1" in + setenv|unsetenv|usleep|random|srandom|seteuid|mkstemps|mkstemp|revoke|vsnprintf|strlcpy|strlcat) + kde_cv_proto_$1="yes - in libkdefakes" + ;; + *) + kde_cv_proto_$1=unknown + ;; + esac +fi + +if test "x$kde_cv_proto_$1" = xunknown; then + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + kde_safe_libs=$LIBS + LIBS="$LIBS $X_EXTRA_LIBS" + AC_TRY_LINK([ +$2 + +extern "C" $4; +], +[ +$3 +], +[ kde_cv_func_$1=yes + kde_cv_proto_$1=yes ], + [kde_cv_proto_$1="$1 unavailable"] +) +LIBS=$kde_safe_libs +AC_LANG_RESTORE +fi +]) +AC_MSG_RESULT($kde_cv_proto_$1) + +if test "x$kde_cv_func_$1" = xyes; then + AC_DEFINE(HAVE_$5, 1, [Define if you have $1]) + $6 +fi +if test "x$kde_cv_proto_$1" = xno; then + AC_DEFINE(HAVE_$5_PROTO, 1, + [Define if you have the $1 prototype]) +fi + +AH_VERBATIM([_HAVE_$5_PROTO], +[ +#if !defined(HAVE_$5_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +$4; +#ifdef __cplusplus +} +#endif +#endif +]) +]) + +AC_DEFUN([AC_CHECK_SETENV], +[ + KDE_CHECK_FUNC_EXT(setenv, [ +#include +], + [setenv("VAR", "VALUE", 1);], + [int setenv (const char *, const char *, int)], + [SETENV]) +]) + +AC_DEFUN([AC_CHECK_UNSETENV], +[ + KDE_CHECK_FUNC_EXT(unsetenv, [ +#include +], + [unsetenv("VAR");], + [void unsetenv (const char *)], + [UNSETENV]) +]) + +AC_DEFUN([AC_CHECK_GETDOMAINNAME], +[ + KDE_CHECK_FUNC_EXT(getdomainname, [ +#include +#include +#include +], + [ +char buffer[200]; +getdomainname(buffer, 200); +], + [#include + int getdomainname (char *, size_t)], + [GETDOMAINNAME]) +]) + +AC_DEFUN([AC_CHECK_GETHOSTNAME], +[ + KDE_CHECK_FUNC_EXT(gethostname, [ +#include +#include +], + [ +char buffer[200]; +gethostname(buffer, 200); +], + [int gethostname (char *, unsigned int)], + [GETHOSTNAME]) +]) + +AC_DEFUN([AC_CHECK_USLEEP], +[ + KDE_CHECK_FUNC_EXT(usleep, [ +#include +], + [ +usleep(200); +], + [int usleep (unsigned int)], + [USLEEP]) +]) + + +AC_DEFUN([AC_CHECK_RANDOM], +[ + KDE_CHECK_FUNC_EXT(random, [ +#include +], + [ +random(); +], + [long int random(void)], + [RANDOM]) + + KDE_CHECK_FUNC_EXT(srandom, [ +#include +], + [ +srandom(27); +], + [void srandom(unsigned int)], + [SRANDOM]) + +]) + +AC_DEFUN([AC_CHECK_INITGROUPS], +[ + KDE_CHECK_FUNC_EXT(initgroups, [ +#include +#include +#include +], + [ +char buffer[200]; +initgroups(buffer, 27); +], + [int initgroups(const char *, gid_t)], + [INITGROUPS]) +]) + +AC_DEFUN([AC_CHECK_MKSTEMPS], +[ + KDE_CHECK_FUNC_EXT(mkstemps, [ +#include +#include +], + [ +mkstemps("/tmp/aaaXXXXXX", 6); +], + [int mkstemps(char *, int)], + [MKSTEMPS]) +]) + +AC_DEFUN([AC_CHECK_MKSTEMP], +[ + KDE_CHECK_FUNC_EXT(mkstemp, [ +#include +#include +], + [ +mkstemp("/tmp/aaaXXXXXX"); +], + [int mkstemp(char *)], + [MKSTEMP]) +]) + +AC_DEFUN([AC_CHECK_MKDTEMP], +[ + KDE_CHECK_FUNC_EXT(mkdtemp, [ +#include +#include +], + [ +mkdtemp("/tmp/aaaXXXXXX"); +], + [char *mkdtemp(char *)], + [MKDTEMP]) +]) + + +AC_DEFUN([AC_CHECK_RES_INIT], +[ + AC_MSG_CHECKING([if res_init needs -lresolv]) + kde_libs_safe="$LIBS" + LIBS="$LIBS $X_EXTRA_LIBS -lresolv" + AC_TRY_LINK( + [ +#include +#include +#include +#include + ], + [ + res_init(); + ], + [ + LIBRESOLV="-lresolv" + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RES_INIT, 1, [Define if you have the res_init function]) + ], + [ AC_MSG_RESULT(no) ] + ) + LIBS=$kde_libs_safe + AC_SUBST(LIBRESOLV) + + KDE_CHECK_FUNC_EXT(res_init, + [ +#include +#include +#include +#include + ], + [res_init()], + [int res_init(void)], + [RES_INIT]) +]) + +AC_DEFUN([AC_CHECK_STRLCPY], +[ + KDE_CHECK_FUNC_EXT(strlcpy, [ +#include +], +[ char buf[20]; + strlcpy(buf, "KDE function test", sizeof(buf)); +], + [unsigned long strlcpy(char*, const char*, unsigned long)], + [STRLCPY]) +]) + +AC_DEFUN([AC_CHECK_STRLCAT], +[ + KDE_CHECK_FUNC_EXT(strlcat, [ +#include +], +[ char buf[20]; + buf[0]='\0'; + strlcat(buf, "KDE function test", sizeof(buf)); +], + [unsigned long strlcat(char*, const char*, unsigned long)], + [STRLCAT]) +]) + +AC_DEFUN([AC_CHECK_RES_QUERY], +[ + KDE_CHECK_FUNC_EXT(res_query, [ +#include +#include +#include +#include +#include +], +[ +res_query(NULL, 0, 0, NULL, 0); +], + [int res_query(const char *, int, int, unsigned char *, int)], + [RES_QUERY]) +]) + +AC_DEFUN([AC_CHECK_DN_SKIPNAME], +[ + KDE_CHECK_FUNC_EXT(dn_skipname, [ +#include +#include +#include +#include +], +[ +dn_skipname (NULL, NULL); +], + [int dn_skipname (unsigned char *, unsigned char *)], + [DN_SKIPNAME]) +]) + + +AC_DEFUN([AC_FIND_GIF], + [AC_MSG_CHECKING([for giflib]) +AC_CACHE_VAL(ac_cv_lib_gif, +[ac_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$all_libraries -lgif -lX11 $LIBSOCKET" +else +LIBS="$all_libraries -lgif" +fi +AC_TRY_LINK(dnl +[ +#ifdef __cplusplus +extern "C" { +#endif +int GifLastError(void); +#ifdef __cplusplus +} +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +], + [return GifLastError();], + eval "ac_cv_lib_gif=yes", + eval "ac_cv_lib_gif=no") +LIBS="$ac_save_LIBS" +])dnl +if eval "test \"`echo $ac_cv_lib_gif`\" = yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_LIBGIF, 1, [Define if you have libgif]) +else + AC_MSG_ERROR(You need giflib30. Please install the kdesupport package) +fi +]) + +AC_DEFUN([KDE_FIND_JPEG_HELPER], +[ +AC_MSG_CHECKING([for libjpeg$2]) +AC_CACHE_VAL(ac_cv_lib_jpeg_$1, +[ +ac_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -ljpeg$2 -lm" +ac_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK( +[ +#ifdef __cplusplus +extern "C" { +#endif +void jpeg_CreateDecompress(); +#ifdef __cplusplus +} +#endif +], +[jpeg_CreateDecompress();], + eval "ac_cv_lib_jpeg_$1=-ljpeg$2", + eval "ac_cv_lib_jpeg_$1=no") +LIBS="$ac_save_LIBS" +CFLAGS="$ac_save_CFLAGS" +]) + +if eval "test ! \"`echo $ac_cv_lib_jpeg_$1`\" = no"; then + LIBJPEG="$ac_cv_lib_jpeg_$1" + AC_MSG_RESULT($ac_cv_lib_jpeg_$1) +else + AC_MSG_RESULT(no) + $3 +fi + +]) + +AC_DEFUN([AC_FIND_JPEG], +[ +dnl first look for libraries +KDE_FIND_JPEG_HELPER(6b, 6b, + KDE_FIND_JPEG_HELPER(normal, [], + [ + LIBJPEG= + ] + ) +) + +dnl then search the headers (can't use simply AC_TRY_xxx, as jpeglib.h +dnl requires system dependent includes loaded before it) +jpeg_incdirs="$includedir /usr/include /usr/local/include $kde_extra_includes" +AC_FIND_FILE(jpeglib.h, $jpeg_incdirs, jpeg_incdir) +test "x$jpeg_incdir" = xNO && jpeg_incdir= + +dnl if headers _and_ libraries are missing, this is no error, and we +dnl continue with a warning (the user will get no jpeg support in khtml) +dnl if only one is missing, it means a configuration error, but we still +dnl only warn +if test -n "$jpeg_incdir" && test -n "$LIBJPEG" ; then + AC_DEFINE_UNQUOTED(HAVE_LIBJPEG, 1, [Define if you have libjpeg]) +else + if test -n "$jpeg_incdir" || test -n "$LIBJPEG" ; then + AC_MSG_WARN([ +There is an installation error in jpeg support. You seem to have only one +of either the headers _or_ the libraries installed. You may need to either +provide correct --with-extra-... options, or the development package of +libjpeg6b. You can get a source package of libjpeg from http://www.ijg.org/ +Disabling JPEG support. +]) + else + AC_MSG_WARN([libjpeg not found. disable JPEG support.]) + fi + jpeg_incdir= + LIBJPEG= +fi + +AC_SUBST(LIBJPEG) +AH_VERBATIM(_AC_CHECK_JPEG, +[/* + * jpeg.h needs HAVE_BOOLEAN, when the system uses boolean in system + * headers and I'm too lazy to write a configure test as long as only + * unixware is related + */ +#ifdef _UNIXWARE +#define HAVE_BOOLEAN +#endif +]) +]) + +AC_DEFUN([KDE_CHECK_QT_JPEG], +[ +if test -n "$LIBJPEG"; then +AC_MSG_CHECKING([if Qt needs $LIBJPEG]) +AC_CACHE_VAL(kde_cv_qt_jpeg, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS $LIBQT" +LIBS=`echo $LIBS | sed "s/$LIBJPEG//"` +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK( +[#include ], + [ + int argc; + char** argv; + QApplication app(argc, argv);], + eval "kde_cv_qt_jpeg=no", + eval "kde_cv_qt_jpeg=yes") +LIBS="$ac_save_LIBS" +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE +fi +]) + +if eval "test ! \"`echo $kde_cv_qt_jpeg`\" = no"; then + AC_MSG_RESULT(yes) + LIBJPEG_QT='$(LIBJPEG)' +else + AC_MSG_RESULT(no) + LIBJPEG_QT= +fi + +]) + +AC_DEFUN([AC_FIND_ZLIB], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_MSG_CHECKING([for libz]) +AC_CACHE_VAL(ac_cv_lib_z, +[ +kde_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -lz $LIBSOCKET" +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK(dnl +[ +#include +], +[ + char buf[42]; + gzFile f = (gzFile) 0; + /* this would segfault.. but we only link, don't run */ + (void) gzgets(f, buf, sizeof(buf)); + + return (zlibVersion() == ZLIB_VERSION); +], + eval "ac_cv_lib_z='-lz'", + eval "ac_cv_lib_z=no") +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if test ! "$ac_cv_lib_z" = no; then + AC_DEFINE_UNQUOTED(HAVE_LIBZ, 1, [Define if you have libz]) + LIBZ="$ac_cv_lib_z" + AC_MSG_RESULT($ac_cv_lib_z) +else + AC_MSG_ERROR(not found. + Possibly configure picks up an outdated version + installed by XFree86. Remove it from your system. + + Check your installation and look into config.log) + LIBZ="" +fi +AC_SUBST(LIBZ) +]) + +AC_DEFUN([KDE_TRY_TIFFLIB], +[ +AC_MSG_CHECKING([for libtiff $1]) + +AC_CACHE_VAL(kde_cv_libtiff_$1, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$all_libraries $USER_LDFLAGS -l$1 $LIBJPEG $LIBZ -lX11 $LIBSOCKET -lm" +else +LIBS="$all_libraries $USER_LDFLAGS -l$1 $LIBJPEG $LIBZ -lm" +fi +kde_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl +[ +#include +], + [return (TIFFOpen( "", "r") == 0); ], +[ + kde_cv_libtiff_$1="-l$1 $LIBJPEG $LIBZ" +], [ + kde_cv_libtiff_$1=no +]) + +LIBS="$kde_save_LIBS" +CXXFLAGS="$kde_save_CXXFLAGS" +AC_LANG_RESTORE +]) + +if test "$kde_cv_libtiff_$1" = "no"; then + AC_MSG_RESULT(no) + LIBTIFF="" + $3 +else + LIBTIFF="$kde_cv_libtiff_$1" + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_LIBTIFF, 1, [Define if you have libtiff]) + $2 +fi + +]) + +AC_DEFUN([AC_FIND_TIFF], +[ +AC_REQUIRE([K_PATH_X]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_REQUIRE([AC_FIND_JPEG]) +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + +KDE_TRY_TIFFLIB(tiff, [], + KDE_TRY_TIFFLIB(tiff34)) + +AC_SUBST(LIBTIFF) +]) + +AC_DEFUN([KDE_FIND_LIBEXR], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_CACHE_VAL(ac_cv_libexr, +[ + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + AC_MSG_CHECKING([for OpenEXR libraries]) + + if test "$PKG_CONFIG" = "no" ; then + AC_MSG_RESULT(no) + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + if !(`$PKG_CONFIG --exists OpenEXR`) ; then + AC_MSG_RESULT(no) + EXRSTATUS=no + else + if !(`$PKG_CONFIG --atleast-version="1.1.1" OpenEXR`) ; then + AC_MSG_RESULT(no) + EXRSTATUS=old + else + kde_save_LIBS="$LIBS" + LIBS="$LIBS $all_libraries $USER_LDFLAGS `pkg-config --libs OpenEXR` $LIBZ" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + kde_save_CXXFLAGS="$CXXFLAGS" + EXR_FLAGS=`$PKG_CONFIG --cflags OpenEXR` + CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES $EXR_FLAGS" + + AC_TRY_LINK(dnl + [ + #include + ], + [ + using namespace Imf; + RgbaInputFile file ("dummy"); + return 0; + ], + eval "ac_cv_libexr='`pkg-config --libs OpenEXR`'", + eval "ac_cv_libexr=no" + ) + LIBS="$kde_save_LIBS" + CXXFLAGS="$kde_save_CXXFLAGS" + AC_LANG_RESTORE + ])dnl + if eval "test ! \"`echo $ac_cv_libexr`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_EXR, 1, [Define if you have OpenEXR]) + LIB_EXR="$ac_cv_libexr" + AC_MSG_RESULT($ac_cv_libexr) + else + AC_MSG_RESULT(no) + LIB_EXR="" + fi + fi + fi + fi + AC_SUBST(LIB_EXR) + AC_SUBST(EXR_FLAGS) +]) + + + +AC_DEFUN([AC_FIND_PNG], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_MSG_CHECKING([for libpng]) +AC_CACHE_VAL(ac_cv_lib_png, +[ +kde_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$LIBS $all_libraries $USER_LDFLAGS -lpng $LIBZ -lm -lX11 $LIBSOCKET" +else +LIBS="$LIBS $all_libraries $USER_LDFLAGS -lpng $LIBZ -lm" +fi +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl + [ + #include + ], + [ + png_structp png_ptr = png_create_read_struct( /* image ptr */ + PNG_LIBPNG_VER_STRING, 0, 0, 0 ); + return( png_ptr != 0 ); + ], + eval "ac_cv_lib_png='-lpng $LIBZ -lm'", + eval "ac_cv_lib_png=no" +) +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if eval "test ! \"`echo $ac_cv_lib_png`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_LIBPNG, 1, [Define if you have libpng]) + LIBPNG="$ac_cv_lib_png" + AC_SUBST(LIBPNG) + AC_MSG_RESULT($ac_cv_lib_png) +else + AC_MSG_RESULT(no) + LIBPNG="" + AC_SUBST(LIBPNG) +fi +]) + + +AC_DEFUN([AC_FIND_JASPER], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_JPEG]) +AC_MSG_CHECKING([for jasper]) +AC_CACHE_VAL(ac_cv_jasper, +[ +kde_save_LIBS="$LIBS" +LIBS="$LIBS $all_libraries $USER_LDFLAGS -ljasper $LIBJPEG -lm" +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl + [ + #include + ], + [ + return( jas_init() ); + ], + eval "ac_cv_jasper='-ljasper $LIBJPEG -lm'", + eval "ac_cv_jasper=no" +) +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if eval "test ! \"`echo $ac_cv_jasper`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_JASPER, 1, [Define if you have jasper]) + LIB_JASPER="$ac_cv_jasper" + AC_MSG_RESULT($ac_cv_jasper) +else + AC_MSG_RESULT(no) + LIB_JASPER="" +fi +AC_SUBST(LIB_JASPER) +]) + +AC_DEFUN([AC_CHECK_BOOL], +[ + AC_DEFINE_UNQUOTED(HAVE_BOOL, 1, [You _must_ have bool]) +]) + +AC_DEFUN([AC_CHECK_GNU_EXTENSIONS], +[ +AC_MSG_CHECKING(if you need GNU extensions) +AC_CACHE_VAL(ac_cv_gnu_extensions, +[ +cat > conftest.c << EOF +#include + +#ifdef __GNU_LIBRARY__ +yes +#endif +EOF + +if (eval "$ac_cpp conftest.c") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_gnu_extensions=yes +else + ac_cv_gnu_extensions=no +fi +]) + +AC_MSG_RESULT($ac_cv_gnu_extensions) +if test "$ac_cv_gnu_extensions" = "yes"; then + AC_DEFINE_UNQUOTED(_GNU_SOURCE, 1, [Define if you need to use the GNU extensions]) +fi +]) + +AC_DEFUN([KDE_CHECK_COMPILER_FLAG], +[ +AC_MSG_CHECKING([whether $CXX supports -$1]) +kde_cache=`echo $1 | sed 'y% .=/+-,%____p__%'` +AC_CACHE_VAL(kde_cv_prog_cxx_$kde_cache, +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -$1" + AC_TRY_LINK([],[ return 0; ], [eval "kde_cv_prog_cxx_$kde_cache=yes"], []) + CXXFLAGS="$save_CXXFLAGS" + AC_LANG_RESTORE +]) +if eval "test \"`echo '$kde_cv_prog_cxx_'$kde_cache`\" = yes"; then + AC_MSG_RESULT(yes) + : + $2 +else + AC_MSG_RESULT(no) + : + $3 +fi +]) + +AC_DEFUN([KDE_CHECK_C_COMPILER_FLAG], +[ +AC_MSG_CHECKING([whether $CC supports -$1]) +kde_cache=`echo $1 | sed 'y% .=/+-,%____p__%'` +AC_CACHE_VAL(kde_cv_prog_cc_$kde_cache, +[ + AC_LANG_SAVE + AC_LANG_C + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -$1" + AC_TRY_LINK([],[ return 0; ], [eval "kde_cv_prog_cc_$kde_cache=yes"], []) + CFLAGS="$save_CFLAGS" + AC_LANG_RESTORE +]) +if eval "test \"`echo '$kde_cv_prog_cc_'$kde_cache`\" = yes"; then + AC_MSG_RESULT(yes) + : + $2 +else + AC_MSG_RESULT(no) + : + $3 +fi +]) + + +dnl AC_REMOVE_FORBIDDEN removes forbidden arguments from variables +dnl use: AC_REMOVE_FORBIDDEN(CC, [-forbid -bad-option whatever]) +dnl it's all white-space separated +AC_DEFUN([AC_REMOVE_FORBIDDEN], +[ __val=$$1 + __forbid=" $2 " + if test -n "$__val"; then + __new="" + ac_save_IFS=$IFS + IFS=" " + for i in $__val; do + case "$__forbid" in + *" $i "*) AC_MSG_WARN([found forbidden $i in $1, removing it]) ;; + *) # Careful to not add spaces, where there were none, because otherwise + # libtool gets confused, if we change e.g. CXX + if test -z "$__new" ; then __new=$i ; else __new="$__new $i" ; fi ;; + esac + done + IFS=$ac_save_IFS + $1=$__new + fi +]) + + +AC_DEFUN([KDE_CHECK_FOR_BAD_COMPILER], +[ + AC_MSG_CHECKING([whether $CC is blacklisted]) + + dnl In theory we have tu run this test against $CC and $CXX + dnl in C and in C++ mode, because its perfectly legal for + dnl the user to mix compiler versions, since C has a defined + dnl ABI. + dnl + dnl For now, we assume the user is not on crack. + + AC_TRY_COMPILE([ +#ifdef __GNUC__ +#if __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 0 +choke me +#endif +#endif +], , + kde_bad_compiler=no, + kde_bad_compiler=yes +) + + AC_MSG_RESULT($kde_bad_compiler) + +if test "$kde_bad_compiler" = "yes"; then + AC_MSG_ERROR([ + +This particular compiler version is blacklisted because it +is known to miscompile KDE. Please use a newer version, or +if that is not yet available, choose an older version. + +Please do not report a bug or bother us reporting this +configure error. We know about it, and we introduced +it by intention to avoid untraceable bugs or crashes in KDE. + +]) +fi + +]) + + +AC_DEFUN([KDE_CHECK_FOR_OPT_NOINLINE_MATCH], +[ + AC_CACHE_CHECK([whether system headers can cope with -O2 -fno-inline], + kde_cv_opt_noinline_match, + [ + kde_cv_opt_noinline_match=irrelevant + dnl if we don't use both -O2 and -fno-inline, this check is moot + if echo "$CFLAGS" | grep -e -O2 >/dev/null 2>/dev/null \ + && echo "$CFLAGS" | grep -e -fno-inline >/dev/null 2>/dev/null ; then + + ac_cflags_save="$CFLAGS" + CFLAGS="$CFLAGS -D_USE_GNU" + + AC_TRY_LINK([ + #include +], [ const char *pt, *et; + et = __extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p ( ";," ) && ((size_t)(const void *)(( ";," )+ 1) - (size_t)(const void *)( ";," ) == 1) ? ((__a0 =((__const char *) ( ";," ))[0], __a0 == '\0') ? ((void) ( pt ),((void *)0) ) : ((__a1 = ((__const char *) ( ";," ))[1], __a1== '\0') ? (__extension__ (__builtin_constant_p ( __a0 ) && ( __a0 ) == '\0' ? (char *) __rawmemchr ( pt , __a0) : strchr( pt , __a0 ))) : ((__a2 = ((__const char *) ( ";," ))[2], __a2 == '\0') ? __strpbrk_c2 ( pt , __a0, __a1) :(((__const char *) ( ";," ))[3] == '\0' ? __strpbrk_c3 ( pt ,__a0, __a1, __a2): strpbrk ( pt , ";," ))))) : strpbrk ( pt , ";," )); }) ; +], + kde_cv_opt_noinline_match=yes, + kde_cv_opt_noinline_match=no + ) + + CFLAGS="$ac_cflags_save" + fi + ]) +]) + + +dnl AC_VALIDIFY_CXXFLAGS checks for forbidden flags the user may have given +AC_DEFUN([AC_VALIDIFY_CXXFLAGS], +[dnl +if test "x$kde_use_qt_emb" != "xyes"; then + AC_REMOVE_FORBIDDEN(CXX, [-fno-rtti -rpath]) + AC_REMOVE_FORBIDDEN(CXXFLAGS, [-fno-rtti -rpath]) +else + AC_REMOVE_FORBIDDEN(CXX, [-rpath]) + AC_REMOVE_FORBIDDEN(CXXFLAGS, [-rpath]) +fi +]) + +AC_DEFUN([AC_CHECK_COMPILERS], +[ + AC_ARG_ENABLE(debug, + AC_HELP_STRING([--enable-debug=ARG],[enables debug symbols (yes|no|full) [default=no]]), + [ + case $enableval in + yes) + kde_use_debug_code="yes" + kde_use_debug_define=no + ;; + full) + kde_use_debug_code="full" + kde_use_debug_define=no + ;; + *) + kde_use_debug_code="no" + kde_use_debug_define=yes + ;; + esac + ], + [kde_use_debug_code="no" + kde_use_debug_define=no + ]) + + dnl Just for configure --help + AC_ARG_ENABLE(dummyoption, + AC_HELP_STRING([--disable-debug], + [disables debug output and debug symbols [default=no]]), + [],[]) + + AC_ARG_ENABLE(strict, + AC_HELP_STRING([--enable-strict], + [compiles with strict compiler options (may not work!)]), + [ + if test $enableval = "no"; then + kde_use_strict_options="no" + else + kde_use_strict_options="yes" + fi + ], [kde_use_strict_options="no"]) + + AC_ARG_ENABLE(warnings,AC_HELP_STRING([--disable-warnings],[disables compilation with -Wall and similar]), + [ + if test $enableval = "no"; then + kde_use_warnings="no" + else + kde_use_warnings="yes" + fi + ], [kde_use_warnings="yes"]) + + dnl enable warnings for debug build + if test "$kde_use_debug_code" != "no"; then + kde_use_warnings=yes + fi + + AC_ARG_ENABLE(profile,AC_HELP_STRING([--enable-profile],[creates profiling infos [default=no]]), + [kde_use_profiling=$enableval], + [kde_use_profiling="no"] + ) + + dnl this prevents stupid AC_PROG_CC to add "-g" to the default CFLAGS + CFLAGS=" $CFLAGS" + + AC_PROG_CC + + AC_PROG_CPP + + if test "$GCC" = "yes"; then + if test "$kde_use_debug_code" != "no"; then + if test $kde_use_debug_code = "full"; then + CFLAGS="-g3 -fno-inline $CFLAGS" + else + CFLAGS="-g -O2 -fno-schedule-insns -fno-inline $CFLAGS" + fi + else + CFLAGS="-O2 $CFLAGS" + fi + fi + + if test "$kde_use_debug_define" = "yes"; then + CFLAGS="-DNDEBUG $CFLAGS" + fi + + + case "$host" in + *-*-sysv4.2uw*) CFLAGS="-D_UNIXWARE $CFLAGS";; + *-*-sysv5uw7*) CFLAGS="-D_UNIXWARE7 $CFLAGS";; + esac + + if test -z "$LDFLAGS" && test "$kde_use_debug_code" = "no" && test "$GCC" = "yes"; then + LDFLAGS="" + fi + + CXXFLAGS=" $CXXFLAGS" + + AC_PROG_CXX + + KDE_CHECK_FOR_BAD_COMPILER + + if test "$GXX" = "yes" || test "$CXX" = "KCC"; then + if test "$kde_use_debug_code" != "no"; then + if test "$CXX" = "KCC"; then + CXXFLAGS="+K0 -Wall -pedantic -W -Wpointer-arith -Wwrite-strings $CXXFLAGS" + else + if test "$kde_use_debug_code" = "full"; then + CXXFLAGS="-g3 -fno-inline $CXXFLAGS" + else + CXXFLAGS="-g -O2 -fno-schedule-insns -fno-inline $CXXFLAGS" + fi + fi + KDE_CHECK_COMPILER_FLAG(fno-builtin,[CXXFLAGS="-fno-builtin $CXXFLAGS"]) + + dnl convenience compiler flags + KDE_CHECK_COMPILER_FLAG(Woverloaded-virtual, [WOVERLOADED_VIRTUAL="-Woverloaded-virtual"], [WOVERLOADED_VRITUAL=""]) + AC_SUBST(WOVERLOADED_VIRTUAL) + else + if test "$CXX" = "KCC"; then + CXXFLAGS="+K3 $CXXFLAGS" + else + CXXFLAGS="-O2 $CXXFLAGS" + fi + fi + fi + + if test "$kde_use_debug_define" = "yes"; then + CXXFLAGS="-DNDEBUG -DNO_DEBUG $CXXFLAGS" + fi + + if test "$kde_use_profiling" = "yes"; then + KDE_CHECK_COMPILER_FLAG(pg, + [ + CFLAGS="-pg $CFLAGS" + CXXFLAGS="-pg $CXXFLAGS" + ]) + fi + + if test "$kde_use_warnings" = "yes"; then + if test "$GCC" = "yes"; then + CXXFLAGS="-Wall -W -Wpointer-arith $CXXFLAGS" + case $host in + *-*-linux-gnu) + CFLAGS="-std=iso9899:1990 -W -Wall -Wchar-subscripts -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -D_XOPEN_SOURCE=500 -D_BSD_SOURCE $CFLAGS" + CXXFLAGS="-ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wchar-subscripts $CXXFLAGS" + KDE_CHECK_COMPILER_FLAG(Wmissing-format-attribute, [CXXFLAGS="$CXXFLAGS -Wformat-security -Wmissing-format-attribute"]) + KDE_CHECK_C_COMPILER_FLAG(Wmissing-format-attribute, [CFLAGS="$CFLAGS -Wformat-security -Wmissing-format-attribute"]) + ;; + esac + KDE_CHECK_COMPILER_FLAG(Wundef,[CXXFLAGS="-Wundef $CXXFLAGS"]) + KDE_CHECK_COMPILER_FLAG(Wno-long-long,[CXXFLAGS="-Wno-long-long $CXXFLAGS"]) + dnl ### FIXME: revert for KDE 4 + KDE_CHECK_COMPILER_FLAG(Wno-non-virtual-dtor,[CXXFLAGS="$CXXFLAGS -Wno-non-virtual-dtor"]) + fi + fi + + if test "$GXX" = "yes" && test "$kde_use_strict_options" = "yes"; then + CXXFLAGS="-Wcast-qual -Wshadow -Wcast-align $CXXFLAGS" + fi + + AC_ARG_ENABLE(pch, + AC_HELP_STRING([--enable-pch], + [enables precompiled header support (currently only KCC or gcc >=3.4+unsermake) [default=no]]), + [ kde_use_pch=$enableval ],[ kde_use_pch=no ]) + + HAVE_GCC_VISIBILITY=0 + AC_SUBST([HAVE_GCC_VISIBILITY]) + + if test "$GXX" = "yes"; then + gcc_no_reorder_blocks=NO + KDE_CHECK_COMPILER_FLAG(fno-reorder-blocks,[gcc_no_reorder_blocks=YES]) + if test $kde_use_debug_code != "no" && \ + test $kde_use_debug_code != "full" && \ + test "YES" = "$gcc_no_reorder_blocks" ; then + CXXFLAGS="$CXXFLAGS -fno-reorder-blocks" + CFLAGS="$CFLAGS -fno-reorder-blocks" + fi + KDE_CHECK_COMPILER_FLAG(fno-exceptions,[CXXFLAGS="$CXXFLAGS -fno-exceptions"]) + KDE_CHECK_COMPILER_FLAG(fno-check-new, [CXXFLAGS="$CXXFLAGS -fno-check-new"]) + KDE_CHECK_COMPILER_FLAG(fno-common, [CXXFLAGS="$CXXFLAGS -fno-common"]) + KDE_CHECK_COMPILER_FLAG(fexceptions, [USE_EXCEPTIONS="-fexceptions"], USE_EXCEPTIONS= ) + ENABLE_PERMISSIVE_FLAG="-fpermissive" + + if test "$kde_use_pch" = "yes"; then + AC_MSG_CHECKING(whether gcc supports precompiling c header files) + echo >conftest.h + if $CC -x c-header conftest.h >/dev/null 2>/dev/null; then + kde_gcc_supports_pch=yes + AC_MSG_RESULT(yes) + else + kde_gcc_supports_pch=no + AC_MSG_RESULT(no) + fi + if test "$kde_gcc_supports_pch" = "yes"; then + AC_MSG_CHECKING(whether gcc supports precompiling c++ header files) + if $CXX -x c++-header conftest.h >/dev/null 2>/dev/null; then + kde_gcc_supports_pch=yes + AC_MSG_RESULT(yes) + else + kde_gcc_supports_pch=no + AC_MSG_RESULT(no) + fi + fi + rm -f conftest.h conftest.h.gch + fi + + KDE_CHECK_FOR_OPT_NOINLINE_MATCH + if test "x$kde_cv_opt_noinline_match" = "xno" ; then + CFLAGS="`echo "$CFLAGS" | sed "s/ -fno-inline//"`" + fi + fi + AM_CONDITIONAL(unsermake_enable_pch, test "$kde_use_pch" = "yes" && test "$kde_gcc_supports_pch" = "yes") + if test "$CXX" = "KCC"; then + dnl unfortunately we currently cannot disable exception support in KCC + dnl because doing so is binary incompatible and Qt by default links with exceptions :-( + dnl KDE_CHECK_COMPILER_FLAG(-no_exceptions,[CXXFLAGS="$CXXFLAGS --no_exceptions"]) + dnl KDE_CHECK_COMPILER_FLAG(-exceptions, [USE_EXCEPTIONS="--exceptions"], USE_EXCEPTIONS= ) + + if test "$kde_use_pch" = "yes"; then + dnl TODO: support --pch-dir! + KDE_CHECK_COMPILER_FLAG(-pch,[CXXFLAGS="$CXXFLAGS --pch"]) + dnl the below works (but the dir must exist), but it's + dnl useless for a whole package. + dnl The are precompiled headers for each source file, so when compiling + dnl from scratch, it doesn't make a difference, and they take up + dnl around ~5Mb _per_ sourcefile. + dnl KDE_CHECK_COMPILER_FLAG(-pch_dir /tmp, + dnl [CXXFLAGS="$CXXFLAGS --pch_dir `pwd`/pcheaders"]) + fi + dnl this flag controls inlining. by default KCC inlines in optimisation mode + dnl all implementations that are defined inside the class {} declaration. + dnl because of templates-compatibility with broken gcc compilers, this + dnl can cause excessive inlining. This flag limits it to a sane level + KDE_CHECK_COMPILER_FLAG(-inline_keyword_space_time=6,[CXXFLAGS="$CXXFLAGS --inline_keyword_space_time=6"]) + KDE_CHECK_COMPILER_FLAG(-inline_auto_space_time=2,[CXXFLAGS="$CXXFLAGS --inline_auto_space_time=2"]) + KDE_CHECK_COMPILER_FLAG(-inline_implicit_space_time=2.0,[CXXFLAGS="$CXXFLAGS --inline_implicit_space_time=2.0"]) + KDE_CHECK_COMPILER_FLAG(-inline_generated_space_time=2.0,[CXXFLAGS="$CXXFLAGS --inline_generated_space_time=2.0"]) + dnl Some source files are shared between multiple executables + dnl (or libraries) and some of those need template instantiations. + dnl In that case KCC needs to compile those sources with + dnl --one_instantiation_per_object. To make it easy for us we compile + dnl _all_ objects with that flag (--one_per is a shorthand). + KDE_CHECK_COMPILER_FLAG(-one_per, [CXXFLAGS="$CXXFLAGS --one_per"]) + fi + AC_SUBST(USE_EXCEPTIONS) + dnl obsolete macro - provided to keep things going + USE_RTTI= + AC_SUBST(USE_RTTI) + + case "$host" in + *-*-irix*) test "$GXX" = yes && CXXFLAGS="-D_LANGUAGE_C_PLUS_PLUS -D__LANGUAGE_C_PLUS_PLUS $CXXFLAGS" ;; + *-*-sysv4.2uw*) CXXFLAGS="-D_UNIXWARE $CXXFLAGS";; + *-*-sysv5uw7*) CXXFLAGS="-D_UNIXWARE7 $CXXFLAGS";; + *-*-solaris*) + if test "$GXX" = yes; then + libstdcpp=`$CXX -print-file-name=libstdc++.so` + if test ! -f $libstdcpp; then + AC_MSG_ERROR([You've compiled gcc without --enable-shared. This doesn't work with KDE. Please recompile gcc with --enable-shared to receive a libstdc++.so]) + fi + fi + ;; + esac + + AC_VALIDIFY_CXXFLAGS + + AC_PROG_CXXCPP + + if test "$GCC" = yes; then + NOOPT_CFLAGS=-O0 + fi + KDE_CHECK_COMPILER_FLAG(O0,[NOOPT_CXXFLAGS=-O0]) + + AC_ARG_ENABLE(coverage, + AC_HELP_STRING([--enable-coverage],[use gcc coverage testing]), [ + if test "$am_cv_CC_dependencies_compiler_type" = "gcc3"; then + ac_coverage_compiler="-fprofile-arcs -ftest-coverage" + ac_coverage_linker="-lgcc" + elif test "$am_cv_CC_dependencies_compiler_type" = "gcc"; then + ac_coverage_compiler="-fprofile-arcs -ftest-coverage" + ac_coverage_linker="" + else + AC_MSG_ERROR([coverage with your compiler is not supported]) + fi + CFLAGS="$CFLAGS $ac_coverage_compiler" + CXXFLAGS="$CXXFLAGS $ac_coverage_compiler" + LDFLAGS="$LDFLAGS $ac_coverage_linker" + ]) + + AC_SUBST(NOOPT_CXXFLAGS) + AC_SUBST(NOOPT_CFLAGS) + AC_SUBST(ENABLE_PERMISSIVE_FLAG) + + KDE_CHECK_NEW_LDFLAGS + KDE_CHECK_FINAL + KDE_CHECK_CLOSURE + KDE_CHECK_NMCHECK + + ifdef([AM_DEPENDENCIES], AC_REQUIRE([KDE_ADD_DEPENDENCIES]), []) +]) + +AC_DEFUN([KDE_CHECK_VISIBILITY_GCC_BUG], + [ + AC_CACHE_CHECK([for gcc -fvisibility-inlines-hidden bug], kde_cv_val_gcc_visibility_bug, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + safe_CXXFLAGS=$CXXFLAGS + safe_LDFLAGS=$LDFLAGS + CXXFLAGS="$CXXFLAGS -fPIC -fvisibility-inlines-hidden -O0" + LDFLAGS="$LDFLAGS -shared -fPIC" + + AC_TRY_LINK( + [ + /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19664 */ + #include + int some_function( void ) __attribute__ ((visibility("default"))); + int some_function( void ) + { + std::string s("blafasel"); + return 0; + } + ], [/* elvis is alive */], + kde_cv_val_gcc_visibility_bug=no, kde_cv_val_gcc_visibility_bug=yes) + + CXXFLAGS=$safe_CXXFLAGS + LDFLAGS=$safe_LDFLAGS + AC_LANG_RESTORE + ] + ) + + if test x$kde_cv_val_gcc_visibility_bug = xno; then + CXXFLAGS="$CXXFLAGS -fvisibility-inlines-hidden" + fi + ] +) + +AC_DEFUN([KDE_ENABLE_HIDDEN_VISIBILITY], +[ + AC_BEFORE([AC_PATH_QT_1_3], [KDE_ENABLE_HIDDEN_VISIBILITY]) + + AC_MSG_CHECKING([grepping for visibility push/pop in headers]) + + if test "x$GXX" = "xyes"; then + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_EGREP_CPP( + [GCC visibility push], + [ #include + ], + [ + AC_MSG_RESULT(yes) + kde_stdc_visibility_patched=yes ], + [ + AC_MSG_RESULT(no) + AC_MSG_WARN([Your libstdc++ doesn't appear to be patched for + visibility support. Disabling -fvisibility=hidden]) + + kde_stdc_visibility_patched=no ]) + + AC_LANG_RESTORE + + kde_have_gcc_visibility=no + KDE_CHECK_COMPILER_FLAG(fvisibility=hidden, + [ + kde_have_gcc_visibility=yes + dnl the whole toolchain is just a mess, gcc is just too buggy + dnl to handle STL with visibility enabled. Lets reconsider + dnl when gcc 4.2 is out or when things get fixed in the compiler. + dnl Contact mueller@kde.org for details. + AC_ARG_ENABLE(gcc-hidden-visibility, + AC_HELP_STRING([--enable-gcc-hidden-visibility],[toolchain hidden visibility [default=no]]), + [kde_have_gcc_visibility=$enableval], + [kde_have_gcc_visibility=no]) + + AC_CACHE_CHECK([if Qt is patched for -fvisibility], kde_cv_val_qt_gcc_visibility_patched, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + safe_CXXFLAGS=$CXXFLAGS + CXXFLAGS="$CXXFLAGS $all_includes" + + AC_TRY_COMPILE( + [ +#include +#if Q_EXPORT - 0 != 0 +/* if this compiles, then Q_EXPORT is undefined */ +/* if Q_EXPORT is nonempty, this will break compilation */ +#endif + ], [/* elvis is alive */], + kde_cv_val_qt_gcc_visibility_patched=no, kde_cv_val_qt_gcc_visibility_patched=yes) + + CXXFLAGS=$safe_CXXFLAGS + AC_LANG_RESTORE + ] + ) + + if test x$kde_have_gcc_visibility = "xyes" && test x$kde_stdc_visibility_patched = "xyes" && test x$kde_cv_val_qt_gcc_visibility_patched = "xyes"; then + CXXFLAGS="$CXXFLAGS -fvisibility=hidden" + KDE_CHECK_VISIBILITY_GCC_BUG + HAVE_GCC_VISIBILITY=1 + AC_DEFINE_UNQUOTED(__KDE_HAVE_GCC_VISIBILITY, "$HAVE_GCC_VISIBILITY", [define to 1 if -fvisibility is supported]) + fi + ]) + fi +]) + +AC_DEFUN([KDE_ADD_DEPENDENCIES], +[ + [A]M_DEPENDENCIES(CC) + [A]M_DEPENDENCIES(CXX) +]) + +dnl just a wrapper to clean up configure.in +AC_DEFUN([KDE_PROG_LIBTOOL], +[ +AC_REQUIRE([AC_CHECK_COMPILERS]) +AC_REQUIRE([AC_ENABLE_SHARED]) +AC_REQUIRE([AC_ENABLE_STATIC]) + +AC_REQUIRE([AC_LIBTOOL_DLOPEN]) +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_OBJEXT +AC_EXEEXT + +AM_PROG_LIBTOOL +AC_LIBTOOL_CXX + +LIBTOOL_SHELL="/bin/sh ./libtool" +# LIBTOOL="$LIBTOOL --silent" +KDE_PLUGIN="-avoid-version -module -no-undefined \$(KDE_NO_UNDEFINED) \$(KDE_RPATH) \$(KDE_MT_LDFLAGS)" +AC_SUBST(KDE_PLUGIN) + +# This hack ensures that libtool creates shared libs for kunittest plugins. By default check_LTLIBRARIES makes static libs. +KDE_CHECK_PLUGIN="\$(KDE_PLUGIN) -rpath \$(libdir)" +AC_SUBST(KDE_CHECK_PLUGIN) + +# we patch configure quite some so we better keep that consistent for incremental runs +AC_SUBST(AUTOCONF,'$(SHELL) $(top_srcdir)/admin/cvs.sh configure || touch configure') +]) + +AC_DEFUN([KDE_CHECK_LIB64], +[ + AC_ARG_ENABLE(libsuffix, + AC_HELP_STRING([--enable-libsuffix], + [/lib directory suffix (64,32,none,auto[=default])]), + kdelibsuff=$enableval, kdelibsuff="auto") + + if test "$kdelibsuff" = "auto"; then + +cat > conftest.c << EOF +#include +int main() { + return 0; +} +EOF + kdelibsuff=`$CC conftest.c -o conftest.out; ldd conftest.out |sed -ne '/libc.so/{ + s,.*/lib\([[^\/]]*\)/.*,\1, + p +}'` + rm -rf conftest.* + fi + + if test "$kdelibsuff" = "no" || test "$kdelibsuff" = "none"; then + kdelibsuff= + fi + if test -z "$kdelibsuff"; then + AC_MSG_RESULT([not using lib directory suffix]) + AC_DEFINE(KDELIBSUFF, [""], Suffix for lib directories) + else + if test "$libdir" = '${exec_prefix}/lib'; then + libdir="$libdir${kdelibsuff}" + AC_SUBST([libdir], ["$libdir"]) dnl ugly hack for lib64 platforms + fi + AC_DEFINE_UNQUOTED(KDELIBSUFF, ["${kdelibsuff}"], Suffix for lib directories) + AC_MSG_RESULT([using lib directory suffix $kdelibsuff]) + fi +]) + +AC_DEFUN([KDE_CHECK_TYPES], +[ AC_CHECK_SIZEOF(int, 4)dnl + AC_CHECK_SIZEOF(short)dnl + AC_CHECK_SIZEOF(long, 4)dnl + AC_CHECK_SIZEOF(char *, 4)dnl +])dnl + +dnl Not used - kept for compat only? +AC_DEFUN([KDE_DO_IT_ALL], +[ +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM +AM_INIT_AUTOMAKE($1, $2) +AM_DISABLE_LIBRARIES +AC_PREFIX_DEFAULT(${KDEDIR:-/usr/local/kde}) +AC_CHECK_COMPILERS +KDE_PROG_LIBTOOL +AM_KDE_WITH_NLS +AC_PATH_KDE +]) + +AC_DEFUN([AC_CHECK_RPATH], +[ +AC_MSG_CHECKING(for rpath) +AC_ARG_ENABLE(rpath, + AC_HELP_STRING([--disable-rpath],[do not use the rpath feature of ld]), + USE_RPATH=$enableval, USE_RPATH=yes) + +if test -z "$KDE_RPATH" && test "$USE_RPATH" = "yes"; then + + KDE_RPATH="-R \$(libdir)" + + if test "$kde_libraries" != "$libdir"; then + KDE_RPATH="$KDE_RPATH -R \$(kde_libraries)" + fi + + if test -n "$qt_libraries"; then + KDE_RPATH="$KDE_RPATH -R \$(qt_libraries)" + fi + dnl $x_libraries is set to /usr/lib in case + if test -n "$X_LDFLAGS"; then + X_RPATH="-R \$(x_libraries)" + KDE_RPATH="$KDE_RPATH $X_RPATH" + fi + if test -n "$KDE_EXTRA_RPATH"; then + KDE_RPATH="$KDE_RPATH \$(KDE_EXTRA_RPATH)" + fi +fi +AC_SUBST(KDE_EXTRA_RPATH) +AC_SUBST(KDE_RPATH) +AC_SUBST(X_RPATH) +AC_MSG_RESULT($USE_RPATH) +]) + +dnl Check for the type of the third argument of getsockname +AC_DEFUN([AC_CHECK_SOCKLEN_T], +[ + AC_MSG_CHECKING(for socklen_t) + AC_CACHE_VAL(kde_cv_socklen_t, + [ + AC_LANG_PUSH(C++) + kde_cv_socklen_t=no + AC_TRY_COMPILE([ + #include + #include + ], + [ + socklen_t len; + getpeername(0,0,&len); + ], + [ + kde_cv_socklen_t=yes + kde_cv_socklen_t_equiv=socklen_t + ]) + AC_LANG_POP(C++) + ]) + AC_MSG_RESULT($kde_cv_socklen_t) + if test $kde_cv_socklen_t = no; then + AC_MSG_CHECKING([for socklen_t equivalent for socket functions]) + AC_CACHE_VAL(kde_cv_socklen_t_equiv, + [ + kde_cv_socklen_t_equiv=int + AC_LANG_PUSH(C++) + for t in int size_t unsigned long "unsigned long"; do + AC_TRY_COMPILE([ + #include + #include + ], + [ + $t len; + getpeername(0,0,&len); + ], + [ + kde_cv_socklen_t_equiv="$t" + break + ]) + done + AC_LANG_POP(C++) + ]) + AC_MSG_RESULT($kde_cv_socklen_t_equiv) + fi + AC_DEFINE_UNQUOTED(kde_socklen_t, $kde_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined]) + AC_DEFINE_UNQUOTED(ksize_t, $kde_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined (deprecated, use kde_socklen_t)]) +]) + +dnl This is a merge of some macros out of the gettext aclocal.m4 +dnl since we don't need anything, I took the things we need +dnl the copyright for them is: +dnl > +dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +dnl This Makefile.in is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. +dnl > +dnl for this file it is relicensed under LGPL + +AC_DEFUN([AM_KDE_WITH_NLS], + [ + dnl If we use NLS figure out what method + + AM_PATH_PROG_WITH_TEST_KDE(MSGFMT, msgfmt, + [test -n "`$ac_dir/$ac_word --version 2>&1 | grep 'GNU gettext'`"], msgfmt) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + + if test -z "`$GMSGFMT --version 2>&1 | grep 'GNU gettext'`"; then + AC_MSG_RESULT([found msgfmt program is not GNU msgfmt; ignore it]) + GMSGFMT=":" + fi + MSGFMT=$GMSGFMT + AC_SUBST(GMSGFMT) + AC_SUBST(MSGFMT) + + AM_PATH_PROG_WITH_TEST_KDE(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is no GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext programs is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + AC_SUBST(XGETTEXT) + + ]) + +# Search path for a program which passes the given test. +# Ulrich Drepper , 1996. + +# serial 1 +# Stephan Kulow: I appended a _KDE against name conflicts + +dnl AM_PATH_PROG_WITH_TEST_KDE(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN([AM_PATH_PROG_WITH_TEST_KDE], +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + + +# Check whether LC_MESSAGES is available in . +# Ulrich Drepper , 1995. + +# serial 1 + +AC_DEFUN([AM_LC_MESSAGES], + [if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, [Define if your locale.h file contains LC_MESSAGES]) + fi + fi]) + +dnl From Jim Meyering. +dnl FIXME: migrate into libit. + +AC_DEFUN([AM_FUNC_OBSTACK], +[AC_CACHE_CHECK([for obstacks], am_cv_func_obstack, + [AC_TRY_LINK([#include "obstack.h"], + [struct obstack *mem;obstack_free(mem,(char *) 0)], + am_cv_func_obstack=yes, + am_cv_func_obstack=no)]) + if test $am_cv_func_obstack = yes; then + AC_DEFINE(HAVE_OBSTACK) + else + LIBOBJS="$LIBOBJS obstack.o" + fi +]) + +dnl From Jim Meyering. Use this if you use the GNU error.[ch]. +dnl FIXME: Migrate into libit + +AC_DEFUN([AM_FUNC_ERROR_AT_LINE], +[AC_CACHE_CHECK([for error_at_line], am_cv_lib_error_at_line, + [AC_TRY_LINK([],[error_at_line(0, 0, "", 0, "");], + am_cv_lib_error_at_line=yes, + am_cv_lib_error_at_line=no)]) + if test $am_cv_lib_error_at_line = no; then + LIBOBJS="$LIBOBJS error.o" + fi + AC_SUBST(LIBOBJS)dnl +]) + +# Macro to add for using GNU gettext. +# Ulrich Drepper , 1995. + +# serial 1 +# Stephan Kulow: I put a KDE in it to avoid name conflicts + +AC_DEFUN([AM_KDE_GNU_GETTEXT], + [AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + AC_REQUIRE([AC_TYPE_OFF_T])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + AC_REQUIRE([AM_KDE_WITH_NLS])dnl + AC_CHECK_HEADERS([limits.h locale.h nl_types.h string.h values.h alloca.h]) + AC_CHECK_FUNCS([getcwd munmap putenv setlocale strchr strcasecmp \ +__argz_count __argz_stringify __argz_next]) + + AC_MSG_CHECKING(for stpcpy) + AC_CACHE_VAL(kde_cv_func_stpcpy, + [ + kde_safe_cxxflags=$CXXFLAGS + CXXFLAGS="-Werror" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([ + #include + ], + [ + char buffer[200]; + stpcpy(buffer, buffer); + ], + kde_cv_func_stpcpy=yes, + kde_cv_func_stpcpy=no) + AC_LANG_RESTORE + CXXFLAGS=$kde_safe_cxxflags + ]) + AC_MSG_RESULT($kde_cv_func_stpcpy) + if eval "test \"`echo $kde_cv_func_stpcpy`\" = yes"; then + AC_DEFINE(HAVE_STPCPY, 1, [Define if you have stpcpy]) + fi + + AM_LC_MESSAGES + + if test "x$CATOBJEXT" != "x"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for lang in ${LINGUAS=$ALL_LINGUAS}; do + case "$ALL_LINGUAS" in + *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;; + esac + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + ]) + +AC_DEFUN([AC_HAVE_XPM], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$XPM_LDFLAGS" && XPM_LDFLAGS= + test -z "$XPM_INCLUDE" && XPM_INCLUDE= + + AC_ARG_WITH(xpm,AC_HELP_STRING([--without-xpm],[disable color pixmap XPM tests]), + xpm_test=$withval, xpm_test="yes") + if test "x$xpm_test" = xno; then + ac_cv_have_xpm=no + else + AC_MSG_CHECKING(for XPM) + AC_CACHE_VAL(ac_cv_have_xpm, + [ + ac_save_ldflags="$LDFLAGS" + ac_save_cflags="$CFLAGS" + if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then + LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $LDFLAGS $XPM_LDFLAGS $all_libraries -lXpm -lX11 -lXext $LIBZ $LIBSOCKET" + else + LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $LDFLAGS $XPM_LDFLAGS $all_libraries -lXpm $LIBZ $LIBSOCKET" + fi + CFLAGS="$CFLAGS $X_INCLUDES $USER_INCLUDES" + test -n "$XPM_INCLUDE" && CFLAGS="-I$XPM_INCLUDE $CFLAGS" + AC_TRY_LINK([#include ],[], + ac_cv_have_xpm="yes",ac_cv_have_xpm="no") + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + ])dnl + + if test "$ac_cv_have_xpm" = no; then + AC_MSG_RESULT(no) + XPM_LDFLAGS="" + XPMINC="" + $2 + else + AC_DEFINE(HAVE_XPM, 1, [Define if you have XPM support]) + if test "$XPM_LDFLAGS" = ""; then + XPMLIB='-lXpm $(LIB_X11)' + else + XPMLIB="-L$XPM_LDFLAGS -lXpm "'$(LIB_X11)' + fi + if test "$XPM_INCLUDE" = ""; then + XPMINC="" + else + XPMINC="-I$XPM_INCLUDE" + fi + AC_MSG_RESULT(yes) + $1 + fi + fi + AC_SUBST(XPMINC) + AC_SUBST(XPMLIB) +]) + +AC_DEFUN([AC_HAVE_DPMS], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$DPMS_LDFLAGS" && DPMS_LDFLAGS= + test -z "$DPMS_INCLUDE" && DPMS_INCLUDE= + DPMS_LIB= + + AC_ARG_WITH(dpms,AC_HELP_STRING([--without-dpms],[disable DPMS power saving]), + dpms_test=$withval, dpms_test="yes") + if test "x$dpms_test" = xno; then + ac_cv_have_dpms=no + else + AC_MSG_CHECKING(for DPMS) + dnl Note: ac_cv_have_dpms can be no, yes, or -lXdpms. + dnl 'yes' means DPMS_LIB="", '-lXdpms' means DPMS_LIB="-lXdpms". + AC_CACHE_VAL(ac_cv_have_dpms, + [ + if test "x$kde_use_qt_emb" = "xyes" || test "x$kde_use_qt_mac" = "xyes"; then + AC_MSG_RESULT(no) + ac_cv_have_dpms="no" + else + ac_save_ldflags="$LDFLAGS" + ac_save_cflags="$CFLAGS" + ac_save_libs="$LIBS" + LDFLAGS="$LDFLAGS $DPMS_LDFLAGS $all_libraries" + LIBS="-lX11 -lXext $LIBSOCKET" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AC_TRY_LINK([ + #include + #include + #include + #include + int foo_test_dpms() + { return DPMSSetTimeouts( 0, 0, 0, 0 ); }],[], + ac_cv_have_dpms="yes", [ + LIBS="-lXdpms $LIBS" + AC_TRY_LINK([ + #include + #include + #include + #include + int foo_test_dpms() + { return DPMSSetTimeouts( 0, 0, 0, 0 ); }],[], + [ + ac_cv_have_dpms="-lXdpms" + ],ac_cv_have_dpms="no") + ]) + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + LIBS="$ac_save_libs" + fi + ])dnl + + if test "$ac_cv_have_dpms" = no; then + AC_MSG_RESULT(no) + DPMS_LDFLAGS="" + DPMSINC="" + $2 + else + AC_DEFINE(HAVE_DPMS, 1, [Define if you have DPMS support]) + if test "$ac_cv_have_dpms" = "-lXdpms"; then + DPMS_LIB="-lXdpms" + fi + if test "$DPMS_LDFLAGS" = ""; then + DPMSLIB="$DPMS_LIB "'$(LIB_X11)' + else + DPMSLIB="$DPMS_LDFLAGS $DPMS_LIB "'$(LIB_X11)' + fi + if test "$DPMS_INCLUDE" = ""; then + DPMSINC="" + else + DPMSINC="-I$DPMS_INCLUDE" + fi + AC_MSG_RESULT(yes) + $1 + fi + fi + ac_save_cflags="$CFLAGS" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AH_TEMPLATE(HAVE_DPMSCAPABLE_PROTO, + [Define if you have the DPMSCapable prototype in ]) + AC_CHECK_DECL(DPMSCapable, + AC_DEFINE(HAVE_DPMSCAPABLE_PROTO),, + [#include + #include ]) + AH_TEMPLATE(HAVE_DPMSINFO_PROTO, + [Define if you have the DPMSInfo prototype in ]) + AC_CHECK_DECL(DPMSInfo, + AC_DEFINE(HAVE_DPMSINFO_PROTO),, + [#include + #include ]) + CFLAGS="$ac_save_cflags" + AC_SUBST(DPMSINC) + AC_SUBST(DPMSLIB) +]) + +AC_DEFUN([AC_HAVE_GL], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$GL_LDFLAGS" && GL_LDFLAGS= + test -z "$GL_INCLUDE" && GL_INCLUDE= + + AC_ARG_WITH(gl,AC_HELP_STRING([--without-gl],[disable 3D GL modes]), + gl_test=$withval, gl_test="yes") + if test "x$kde_use_qt_emb" = "xyes"; then + # GL and Qt Embedded is a no-go for now. + ac_cv_have_gl=no + elif test "x$gl_test" = xno; then + ac_cv_have_gl=no + else + AC_MSG_CHECKING(for GL) + AC_CACHE_VAL(ac_cv_have_gl, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_ldflags=$LDFLAGS + ac_save_cxxflags=$CXXFLAGS + ac_save_libs=$LIBS + LDFLAGS="$LDFLAGS $GL_LDFLAGS $X_LDFLAGS $all_libraries" + LIBS="$LIBS -lGL -lGLU" + test "x$kde_use_qt_mac" != xyes && test "x$kde_use_qt_emb" != xyes && LIBS="$LIBS -lX11" + LIBS="$LIBS $LIB_XEXT -lm $LIBSOCKET" + CXXFLAGS="$CFLAGS $X_INCLUDES" + test -n "$GL_INCLUDE" && CFLAGS="-I$GL_INCLUDE $CFLAGS" + AC_TRY_LINK([#include +#include +], [], + ac_cv_have_gl="yes", ac_cv_have_gl="no") + AC_LANG_RESTORE + LDFLAGS=$ac_save_ldflags + CXXFLAGS=$ac_save_cxxflags + LIBS=$ac_save_libs + ])dnl + + if test "$ac_cv_have_gl" = "no"; then + AC_MSG_RESULT(no) + GL_LDFLAGS="" + GLINC="" + $2 + else + AC_DEFINE(HAVE_GL, 1, [Defines if you have GL (Mesa, OpenGL, ...)]) + if test "$GL_LDFLAGS" = ""; then + GLLIB='-lGLU -lGL $(LIB_X11)' + else + GLLIB="$GL_LDFLAGS -lGLU -lGL "'$(LIB_X11)' + fi + if test "$GL_INCLUDE" = ""; then + GLINC="" + else + GLINC="-I$GL_INCLUDE" + fi + AC_MSG_RESULT($ac_cv_have_gl) + $1 + fi + fi + AC_SUBST(GLINC) + AC_SUBST(GLLIB) +]) + + + dnl shadow password and PAM magic - maintained by ossi@kde.org + +AC_DEFUN([KDE_PAM], [ + AC_REQUIRE([KDE_CHECK_LIBDL]) + + want_pam= + AC_ARG_WITH(pam, + AC_HELP_STRING([--with-pam[=ARG]],[enable support for PAM: ARG=[yes|no|service name]]), + [ if test "x$withval" = "xyes"; then + want_pam=yes + pam_service=kde + elif test "x$withval" = "xno"; then + want_pam=no + else + want_pam=yes + pam_service=$withval + fi + ], [ pam_service=kde ]) + + use_pam= + PAMLIBS= + if test "x$want_pam" != xno; then + AC_CHECK_LIB(pam, pam_start, [ + AC_CHECK_HEADER(security/pam_appl.h, + [ pam_header=security/pam_appl.h ], + [ AC_CHECK_HEADER(pam/pam_appl.h, + [ pam_header=pam/pam_appl.h ], + [ + AC_MSG_WARN([PAM detected, but no headers found! +Make sure you have the necessary development packages installed.]) + ] + ) + ] + ) + ], , $LIBDL) + if test -z "$pam_header"; then + if test "x$want_pam" = xyes; then + AC_MSG_ERROR([--with-pam was specified, but cannot compile with PAM!]) + fi + else + AC_DEFINE(HAVE_PAM, 1, [Defines if you have PAM (Pluggable Authentication Modules)]) + PAMLIBS="$PAM_MISC_LIB -lpam $LIBDL" + use_pam=yes + + dnl darwin claims to be something special + if test "$pam_header" = "pam/pam_appl.h"; then + AC_DEFINE(HAVE_PAM_PAM_APPL_H, 1, [Define if your PAM headers are in pam/ instead of security/]) + fi + + dnl test whether struct pam_message is const (Linux) or not (Sun) + AC_MSG_CHECKING(for const pam_message) + AC_EGREP_HEADER([struct pam_message], $pam_header, + [ AC_EGREP_HEADER([const struct pam_message], $pam_header, + [AC_MSG_RESULT([const: Linux-type PAM])], + [AC_MSG_RESULT([nonconst: Sun-type PAM]) + AC_DEFINE(PAM_MESSAGE_NONCONST, 1, [Define if your PAM support takes non-const arguments (Solaris)])] + )], + [AC_MSG_RESULT([not found - assume const, Linux-type PAM])]) + fi + fi + + AC_SUBST(PAMLIBS) +]) + +dnl DEF_PAM_SERVICE(arg name, full name, define name) +AC_DEFUN([DEF_PAM_SERVICE], [ + AC_ARG_WITH($1-pam, + AC_HELP_STRING([--with-$1-pam=[val]],[override PAM service from --with-pam for $2]), + [ if test "x$use_pam" = xyes; then + $3_PAM_SERVICE=$withval + else + AC_MSG_ERROR([Cannot use use --with-$1-pam, as no PAM was detected. +You may want to enforce it by using --with-pam.]) + fi + ], + [ if test "x$use_pam" = xyes; then + $3_PAM_SERVICE="$pam_service" + fi + ]) + if test -n "$$3_PAM_SERVICE"; then + AC_MSG_RESULT([The PAM service used by $2 will be $$3_PAM_SERVICE]) + AC_DEFINE_UNQUOTED($3_PAM_SERVICE, "$$3_PAM_SERVICE", [The PAM service to be used by $2]) + fi + AC_SUBST($3_PAM_SERVICE) +]) + +AC_DEFUN([KDE_SHADOWPASSWD], [ + AC_REQUIRE([KDE_PAM]) + + AC_CHECK_LIB(shadow, getspent, + [ LIBSHADOW="-lshadow" + ac_use_shadow=yes + ], + [ dnl for UnixWare + AC_CHECK_LIB(gen, getspent, + [ LIBGEN="-lgen" + ac_use_shadow=yes + ], + [ AC_CHECK_FUNC(getspent, + [ ac_use_shadow=yes ], + [ ac_use_shadow=no ]) + ]) + ]) + AC_SUBST(LIBSHADOW) + AC_SUBST(LIBGEN) + + AC_MSG_CHECKING([for shadow passwords]) + + AC_ARG_WITH(shadow, + AC_HELP_STRING([--with-shadow],[If you want shadow password support]), + [ if test "x$withval" != "xno"; then + use_shadow=yes + else + use_shadow=no + fi + ], [ + use_shadow="$ac_use_shadow" + ]) + + if test "x$use_shadow" = xyes; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SHADOW, 1, [Define if you use shadow passwords]) + else + AC_MSG_RESULT(no) + LIBSHADOW= + LIBGEN= + fi + + dnl finally make the relevant binaries setuid root, if we have shadow passwds. + dnl this still applies, if we could use it indirectly through pam. + if test "x$use_shadow" = xyes || + ( test "x$use_pam" = xyes && test "x$ac_use_shadow" = xyes ); then + case $host in + *-*-freebsd* | *-*-netbsd* | *-*-openbsd*) + SETUIDFLAGS="-m 4755 -o root";; + *) + SETUIDFLAGS="-m 4755";; + esac + fi + AC_SUBST(SETUIDFLAGS) + +]) + +AC_DEFUN([KDE_PASSWDLIBS], [ + AC_REQUIRE([KDE_MISC_TESTS]) dnl for LIBCRYPT + AC_REQUIRE([KDE_PAM]) + AC_REQUIRE([KDE_SHADOWPASSWD]) + + if test "x$use_pam" = "xyes"; then + PASSWDLIBS="$PAMLIBS" + else + PASSWDLIBS="$LIBCRYPT $LIBSHADOW $LIBGEN" + fi + + dnl FreeBSD uses a shadow-like setup, where /etc/passwd holds the users, but + dnl /etc/master.passwd holds the actual passwords. /etc/master.passwd requires + dnl root to read, so kcheckpass needs to be root (even when using pam, since pam + dnl may need to read /etc/master.passwd). + case $host in + *-*-freebsd*) + SETUIDFLAGS="-m 4755 -o root" + ;; + *) + ;; + esac + + AC_SUBST(PASSWDLIBS) +]) + +AC_DEFUN([KDE_CHECK_LIBDL], +[ +AC_CHECK_LIB(dl, dlopen, [ +LIBDL="-ldl" +ac_cv_have_dlfcn=yes +]) + +AC_CHECK_LIB(dld, shl_unload, [ +LIBDL="-ldld" +ac_cv_have_shload=yes +]) + +AC_SUBST(LIBDL) +]) + +AC_DEFUN([KDE_CHECK_DLOPEN], +[ +KDE_CHECK_LIBDL +AC_CHECK_HEADERS(dlfcn.h dl.h) +if test "$ac_cv_header_dlfcn_h" = "no"; then + ac_cv_have_dlfcn=no +fi + +if test "$ac_cv_header_dl_h" = "no"; then + ac_cv_have_shload=no +fi + +dnl XXX why change enable_dlopen? its already set by autoconf's AC_ARG_ENABLE +dnl (MM) +AC_ARG_ENABLE(dlopen, +AC_HELP_STRING([--disable-dlopen],[link statically [default=no]]), +enable_dlopen=$enableval, +enable_dlopen=yes) + +# override the user's opinion, if we know it better ;) +if test "$ac_cv_have_dlfcn" = "no" && test "$ac_cv_have_shload" = "no"; then + enable_dlopen=no +fi + +if test "$ac_cv_have_dlfcn" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_DLFCN, 1, [Define if you have dlfcn]) +fi + +if test "$ac_cv_have_shload" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_SHLOAD, 1, [Define if you have shload]) +fi + +if test "$enable_dlopen" = no ; then + test -n "$1" && eval $1 +else + test -n "$2" && eval $2 +fi + +]) + +AC_DEFUN([KDE_CHECK_DYNAMIC_LOADING], +[ +KDE_CHECK_DLOPEN(libtool_enable_shared=yes, libtool_enable_static=no) +KDE_PROG_LIBTOOL +AC_MSG_CHECKING([dynamic loading]) +eval "`egrep '^build_libtool_libs=' libtool`" +if test "$build_libtool_libs" = "yes" && test "$enable_dlopen" = "yes"; then + dynamic_loading=yes + AC_DEFINE_UNQUOTED(HAVE_DYNAMIC_LOADING) +else + dynamic_loading=no +fi +AC_MSG_RESULT($dynamic_loading) +if test "$dynamic_loading" = "yes"; then + $1 +else + $2 +fi +]) + +AC_DEFUN([KDE_ADD_INCLUDES], +[ +if test -z "$1"; then + test_include="Pix.h" +else + test_include="$1" +fi + +AC_MSG_CHECKING([for libg++ ($test_include)]) + +AC_CACHE_VAL(kde_cv_libgpp_includes, +[ +kde_cv_libgpp_includes=no + + for ac_dir in \ + \ + /usr/include/g++ \ + /usr/include \ + /usr/unsupported/include \ + /opt/include \ + $extra_include \ + ; \ + do + if test -r "$ac_dir/$test_include"; then + kde_cv_libgpp_includes=$ac_dir + break + fi + done +]) + +AC_MSG_RESULT($kde_cv_libgpp_includes) +if test "$kde_cv_libgpp_includes" != "no"; then + all_includes="-I$kde_cv_libgpp_includes $all_includes $USER_INCLUDES" +fi +]) +]) + +AC_DEFUN([KDE_CHECK_LIBPTHREAD], +[ + dnl This code is here specifically to handle the + dnl various flavors of threading library on FreeBSD + dnl 4-, 5-, and 6-, and the (weird) rules around it. + dnl There may be an environment PTHREAD_LIBS that + dnl specifies what to use; otherwise, search for it. + dnl -pthread is special cased and unsets LIBPTHREAD + dnl below if found. + LIBPTHREAD="" + + if test -n "$PTHREAD_LIBS"; then + if test "x$PTHREAD_LIBS" = "x-pthread" ; then + LIBPTHREAD="PTHREAD" + else + PTHREAD_LIBS_save="$PTHREAD_LIBS" + PTHREAD_LIBS=`echo "$PTHREAD_LIBS_save" | sed -e 's,^-l,,g'` + AC_MSG_CHECKING([for pthread_create in $PTHREAD_LIBS]) + KDE_CHECK_LIB($PTHREAD_LIBS, pthread_create, [ + LIBPTHREAD="$PTHREAD_LIBS_save"]) + PTHREAD_LIBS="$PTHREAD_LIBS_save" + fi + fi + + dnl Is this test really needed, in the face of the Tru64 test below? + if test -z "$LIBPTHREAD"; then + AC_CHECK_LIB(pthread, pthread_create, [LIBPTHREAD="-lpthread"]) + fi + + dnl This is a special Tru64 check, see BR 76171 issue #18. + if test -z "$LIBPTHREAD" ; then + AC_MSG_CHECKING([for pthread_create in -lpthread]) + kde_safe_libs=$LIBS + LIBS="$LIBS -lpthread" + AC_TRY_LINK([#include ],[(void)pthread_create(0,0,0,0);],[ + AC_MSG_RESULT(yes) + LIBPTHREAD="-lpthread"],[ + AC_MSG_RESULT(no)]) + LIBS=$kde_safe_libs + fi + + dnl Un-special-case for FreeBSD. + if test "x$LIBPTHREAD" = "xPTHREAD" ; then + LIBPTHREAD="" + fi + + AC_SUBST(LIBPTHREAD) +]) + +AC_DEFUN([KDE_CHECK_PTHREAD_OPTION], +[ + USE_THREADS="" + if test -z "$LIBPTHREAD"; then + KDE_CHECK_COMPILER_FLAG(pthread, [USE_THREADS="-D_THREAD_SAFE -pthread"]) + fi + + AH_VERBATIM(__svr_define, [ +#if defined(__SVR4) && !defined(__svr4__) +#define __svr4__ 1 +#endif +]) + case $host_os in + solaris*) + KDE_CHECK_COMPILER_FLAG(mt, [USE_THREADS="-mt"]) + CPPFLAGS="$CPPFLAGS -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -DUSE_SOLARIS -DSVR4" + ;; + freebsd*) + CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE $PTHREAD_CFLAGS" + ;; + aix*) + CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" + LIBPTHREAD="$LIBPTHREAD -lc_r" + ;; + linux*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" + if test "$CXX" = "KCC"; then + CXXFLAGS="$CXXFLAGS --thread_safe" + NOOPT_CXXFLAGS="$NOOPT_CXXFLAGS --thread_safe" + fi + ;; + *) + ;; + esac + AC_SUBST(USE_THREADS) + AC_SUBST(LIBPTHREAD) +]) + +AC_DEFUN([KDE_CHECK_THREADING], +[ + AC_REQUIRE([KDE_CHECK_LIBPTHREAD]) + AC_REQUIRE([KDE_CHECK_PTHREAD_OPTION]) + dnl default is yes if libpthread is found and no if no libpthread is available + if test -z "$LIBPTHREAD"; then + if test -z "$USE_THREADS"; then + kde_check_threading_default=no + else + kde_check_threading_default=yes + fi + else + kde_check_threading_default=yes + fi + AC_ARG_ENABLE(threading,AC_HELP_STRING([--disable-threading],[disables threading even if libpthread found]), + kde_use_threading=$enableval, kde_use_threading=$kde_check_threading_default) + if test "x$kde_use_threading" = "xyes"; then + AC_DEFINE(HAVE_LIBPTHREAD, 1, [Define if you have a working libpthread (will enable threaded code)]) + fi +]) + +AC_DEFUN([KDE_TRY_LINK_PYTHON], +[ +if test "$kde_python_link_found" = no; then + +if test "$1" = normal; then + AC_MSG_CHECKING(if a Python application links) +else + AC_MSG_CHECKING(if Python depends on $2) +fi + +AC_CACHE_VAL(kde_cv_try_link_python_$1, +[ +kde_save_cflags="$CFLAGS" +CFLAGS="$CFLAGS $PYTHONINC" +kde_save_libs="$LIBS" +LIBS="$LIBS $LIBPYTHON $2 $LIBDL $LIBSOCKET" +kde_save_ldflags="$LDFLAGS" +LDFLAGS="$LDFLAGS $PYTHONLIB" + +AC_TRY_LINK( +[ +#include +],[ + PySys_SetArgv(1, 0); +], + [kde_cv_try_link_python_$1=yes], + [kde_cv_try_link_python_$1=no] +) +CFLAGS="$kde_save_cflags" +LIBS="$kde_save_libs" +LDFLAGS="$kde_save_ldflags" +]) + +if test "$kde_cv_try_link_python_$1" = "yes"; then + AC_MSG_RESULT(yes) + kde_python_link_found=yes + if test ! "$1" = normal; then + LIBPYTHON="$LIBPYTHON $2" + fi + $3 +else + AC_MSG_RESULT(no) + $4 +fi + +fi + +]) + +AC_DEFUN([KDE_CHECK_PYTHON_DIR], +[ +AC_MSG_CHECKING([for Python directory]) + +AC_CACHE_VAL(kde_cv_pythondir, +[ + if test -z "$PYTHONDIR"; then + kde_cv_pythondir=/usr/local + else + kde_cv_pythondir="$PYTHONDIR" + fi +]) + +AC_ARG_WITH(pythondir, +AC_HELP_STRING([--with-pythondir=pythondir],[use python installed in pythondir]), +[ + ac_python_dir=$withval +], ac_python_dir=$kde_cv_pythondir +) + +AC_MSG_RESULT($ac_python_dir) +]) + +AC_DEFUN([KDE_CHECK_PYTHON_INTERN], +[ +AC_REQUIRE([KDE_CHECK_LIBDL]) +AC_REQUIRE([KDE_CHECK_LIBPTHREAD]) +AC_REQUIRE([KDE_CHECK_PYTHON_DIR]) + +if test -z "$1"; then + version="1.5" +else + version="$1" +fi + +AC_MSG_CHECKING([for Python$version]) + +python_incdirs="$ac_python_dir/include /usr/include /usr/local/include/ $kde_extra_includes" +AC_FIND_FILE(Python.h, $python_incdirs, python_incdir) +if test ! -r $python_incdir/Python.h; then + AC_FIND_FILE(python$version/Python.h, $python_incdirs, python_incdir) + python_incdir=$python_incdir/python$version + if test ! -r $python_incdir/Python.h; then + python_incdir=no + fi +fi + +PYTHONINC=-I$python_incdir + +python_libdirs="$ac_python_dir/lib$kdelibsuff /usr/lib$kdelibsuff /usr/local /usr/lib$kdelibsuff $kde_extra_libs" +AC_FIND_FILE(libpython$version.so, $python_libdirs, python_libdir) +if test ! -r $python_libdir/libpython$version.so; then + AC_FIND_FILE(libpython$version.a, $python_libdirs, python_libdir) + if test ! -r $python_libdir/libpython$version.a; then + AC_FIND_FILE(python$version/config/libpython$version.a, $python_libdirs, python_libdir) + python_libdir=$python_libdir/python$version/config + if test ! -r $python_libdir/libpython$version.a; then + python_libdir=no + fi + fi +fi + +PYTHONLIB=-L$python_libdir +kde_orig_LIBPYTHON=$LIBPYTHON +if test -z "$LIBPYTHON"; then + LIBPYTHON=-lpython$version +fi + +AC_FIND_FILE(python$version/copy.py, $python_libdirs, python_moddir) +python_moddir=$python_moddir/python$version +if test ! -r $python_moddir/copy.py; then + python_moddir=no +fi + +PYTHONMODDIR=$python_moddir + +AC_MSG_RESULT(header $python_incdir library $python_libdir modules $python_moddir) + +if test x$python_incdir = xno || test x$python_libdir = xno || test x$python_moddir = xno; then + LIBPYTHON=$kde_orig_LIBPYTHON + test "x$PYTHONLIB" = "x-Lno" && PYTHONLIB="" + test "x$PYTHONINC" = "x-Ino" && PYTHONINC="" + $2 +else + dnl Note: this test is very weak + kde_python_link_found=no + KDE_TRY_LINK_PYTHON(normal) + KDE_TRY_LINK_PYTHON(m, -lm) + KDE_TRY_LINK_PYTHON(pthread, $LIBPTHREAD) + KDE_TRY_LINK_PYTHON(tcl, -ltcl) + KDE_TRY_LINK_PYTHON(db2, -ldb2) + KDE_TRY_LINK_PYTHON(m_and_thread, [$LIBPTHREAD -lm]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_util, [$LIBPTHREAD -lm -lutil]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db3, [$LIBPTHREAD -lm -ldb-3 -lutil]) + KDE_TRY_LINK_PYTHON(pthread_and_db3, [$LIBPTHREAD -ldb-3]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db, [$LIBPTHREAD -lm -ldb -ltermcap -lutil]) + KDE_TRY_LINK_PYTHON(pthread_and_dl, [$LIBPTHREAD $LIBDL -lutil -lreadline -lncurses -lm]) + KDE_TRY_LINK_PYTHON(pthread_and_panel_curses, [$LIBPTHREAD $LIBDL -lm -lpanel -lcurses]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db_special, [$LIBPTHREAD -lm -ldb -lutil], [], + [AC_MSG_WARN([it seems, Python depends on another library. + Please set LIBPYTHON to '-lpython$version -lotherlib' before calling configure to fix this + and contact the authors to let them know about this problem]) + ]) + + LIBPYTHON="$LIBPYTHON $LIBDL $LIBSOCKET" + AC_SUBST(PYTHONINC) + AC_SUBST(PYTHONLIB) + AC_SUBST(LIBPYTHON) + AC_SUBST(PYTHONMODDIR) + AC_DEFINE(HAVE_PYTHON, 1, [Define if you have the development files for python]) +fi + +]) + + +AC_DEFUN([KDE_CHECK_PYTHON], +[ + KDE_CHECK_PYTHON_INTERN("2.5", + [KDE_CHECK_PYTHON_INTERN("2.4", + [KDE_CHECK_PYTHON_INTERN("2.3", + [KDE_CHECK_PYTHON_INTERN("2.2", + [KDE_CHECK_PYTHON_INTERN("2.1", + [KDE_CHECK_PYTHON_INTERN("2.0", + [KDE_CHECK_PYTHON_INTERN($1, $2) ]) + ]) + ]) + ]) + ]) + ]) +]) + +AC_DEFUN([KDE_CHECK_STL], +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="`echo $CXXFLAGS | sed s/-fno-exceptions//`" + + AC_MSG_CHECKING([if C++ programs can be compiled]) + AC_CACHE_VAL(kde_cv_stl_works, + [ + AC_TRY_COMPILE([ +#include +using namespace std; +],[ + string astring="Hallo Welt."; + astring.erase(0, 6); // now astring is "Welt" + return 0; +], kde_cv_stl_works=yes, + kde_cv_stl_works=no) +]) + + AC_MSG_RESULT($kde_cv_stl_works) + + if test "$kde_cv_stl_works" = "yes"; then + # back compatible + AC_DEFINE_UNQUOTED(HAVE_SGI_STL, 1, [Define if you have a STL implementation by SGI]) + else + AC_MSG_ERROR([Your Installation isn't able to compile simple C++ programs. +Check config.log for details - if you're using a Linux distribution you might miss +a package named similar to libstdc++-dev.]) + fi + + CXXFLAGS="$ac_save_CXXFLAGS" + AC_LANG_RESTORE +]) + +AC_DEFUN([AC_FIND_QIMGIO], + [AC_REQUIRE([AC_FIND_JPEG]) +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_MSG_CHECKING([for qimgio]) +AC_CACHE_VAL(ac_cv_lib_qimgio, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_LIBS="$LIBS" +ac_save_CXXFLAGS="$CXXFLAGS" +LIBS="$all_libraries -lqimgio -lpng -lz $LIBJPEG $LIBQT" +CXXFLAGS="$CXXFLAGS -I$qt_incdir $all_includes" +AC_TRY_RUN(dnl +[ +#include +#include +int main() { + QString t = "hallo"; + t.fill('t'); + qInitImageIO(); +} +], + ac_cv_lib_qimgio=yes, + ac_cv_lib_qimgio=no, + ac_cv_lib_qimgio=no) +LIBS="$ac_save_LIBS" +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE +])dnl +if eval "test \"`echo $ac_cv_lib_qimgio`\" = yes"; then + LIBQIMGIO="-lqimgio -lpng -lz $LIBJPEG" + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_QIMGIO, 1, [Define if you have the Qt extension qimgio available]) + AC_SUBST(LIBQIMGIO) +else + AC_MSG_RESULT(not found) +fi +]) + +AC_DEFUN([AM_DISABLE_LIBRARIES], +[ + AC_PROVIDE([AM_ENABLE_STATIC]) + AC_PROVIDE([AM_ENABLE_SHARED]) + enable_static=no + enable_shared=yes +]) + + +AC_DEFUN([AC_CHECK_UTMP_FILE], +[ + AC_MSG_CHECKING([for utmp file]) + + AC_CACHE_VAL(kde_cv_utmp_file, + [ + kde_cv_utmp_file=no + + for ac_file in \ + \ + /var/run/utmp \ + /var/adm/utmp \ + /etc/utmp \ + ; \ + do + if test -r "$ac_file"; then + kde_cv_utmp_file=$ac_file + break + fi + done + ]) + + if test "$kde_cv_utmp_file" != "no"; then + AC_DEFINE_UNQUOTED(UTMP, "$kde_cv_utmp_file", [Define the file for utmp entries]) + $1 + AC_MSG_RESULT($kde_cv_utmp_file) + else + $2 + AC_MSG_RESULT([non found]) + fi +]) + + +AC_DEFUN([KDE_CREATE_SUBDIRSLIST], +[ + +DO_NOT_COMPILE="$DO_NOT_COMPILE CVS debian bsd-port admin" +TOPSUBDIRS="" + +if test ! -s $srcdir/subdirs; then + dnl Note: Makefile.common creates subdirs, so this is just a fallback + files=`cd $srcdir && ls -1` + dirs=`for i in $files; do if test -d $i; then echo $i; fi; done` + for i in $dirs; do + echo $i >> $srcdir/subdirs + done +fi + +ac_topsubdirs= +if test -s $srcdir/inst-apps; then + ac_topsubdirs="`cat $srcdir/inst-apps`" +elif test -s $srcdir/subdirs; then + ac_topsubdirs="`cat $srcdir/subdirs`" +fi + +for i in $ac_topsubdirs; do + AC_MSG_CHECKING([if $i should be compiled]) + if test -d $srcdir/$i; then + install_it="yes" + for j in $DO_NOT_COMPILE; do + if test $i = $j; then + install_it="no" + fi + done + else + install_it="no" + fi + AC_MSG_RESULT($install_it) + vari=`echo $i | sed -e 's,[[-+.@]],_,g'` + if test $install_it = "yes"; then + TOPSUBDIRS="$TOPSUBDIRS $i" + eval "$vari""_SUBDIR_included=yes" + else + eval "$vari""_SUBDIR_included=no" + fi +done + +AC_SUBST(TOPSUBDIRS) +]) + +AC_DEFUN([KDE_CHECK_NAMESPACES], +[ +AC_MSG_CHECKING(whether C++ compiler supports namespaces) +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_TRY_COMPILE([ +], +[ +namespace Foo { + extern int i; + namespace Bar { + extern int i; + } +} + +int Foo::i = 0; +int Foo::Bar::i = 1; +],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NAMESPACES) +], [ +AC_MSG_RESULT(no) +]) +AC_LANG_RESTORE +]) + +dnl ------------------------------------------------------------------------ +dnl Check for S_ISSOCK macro. Doesn't exist on Unix SCO. faure@kde.org +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_CHECK_S_ISSOCK], +[ +AC_MSG_CHECKING(for S_ISSOCK) +AC_CACHE_VAL(ac_cv_have_s_issock, +[ +AC_TRY_LINK( +[ +#include +], +[ +struct stat buff; +int b = S_ISSOCK( buff.st_mode ); +], +ac_cv_have_s_issock=yes, +ac_cv_have_s_issock=no) +]) +AC_MSG_RESULT($ac_cv_have_s_issock) +if test "$ac_cv_have_s_issock" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_S_ISSOCK, 1, [Define if sys/stat.h declares S_ISSOCK.]) +fi + +AH_VERBATIM(_ISSOCK, +[ +#ifndef HAVE_S_ISSOCK +#define HAVE_S_ISSOCK +#define S_ISSOCK(mode) (1==0) +#endif +]) + +]) + +dnl ------------------------------------------------------------------------ +dnl Check for MAXPATHLEN macro, defines KDEMAXPATHLEN. faure@kde.org +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_CHECK_KDEMAXPATHLEN], +[ +AC_MSG_CHECKING(for MAXPATHLEN) +AC_CACHE_VAL(ac_cv_maxpathlen, +[ +cat > conftest.$ac_ext < +#endif +#include +#include +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +KDE_HELLO MAXPATHLEN + +EOF + +ac_try="$ac_cpp conftest.$ac_ext 2>/dev/null | grep '^KDE_HELLO' >conftest.out" + +if AC_TRY_EVAL(ac_try) && test -s conftest.out; then + ac_cv_maxpathlen=`sed 's#KDE_HELLO ##' conftest.out` +else + ac_cv_maxpathlen=1024 +fi + +rm conftest.* + +]) +AC_MSG_RESULT($ac_cv_maxpathlen) +AC_DEFINE_UNQUOTED(KDEMAXPATHLEN,$ac_cv_maxpathlen, [Define a safe value for MAXPATHLEN] ) +]) + +AC_DEFUN([KDE_CHECK_HEADER], +[ + kde_safe_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $all_includes" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_CHECK_HEADER([$1], [$2], [$3], [$4]) + AC_LANG_RESTORE + CPPFLAGS=$kde_safe_cppflags +]) + +AC_DEFUN([KDE_CHECK_HEADERS], +[ + AH_CHECK_HEADERS([$1]) + AC_LANG_SAVE + kde_safe_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $all_includes" + AC_LANG_CPLUSPLUS + AC_CHECK_HEADERS([$1], [$2], [$3], [$4]) + CPPFLAGS=$kde_safe_cppflags + AC_LANG_RESTORE +]) + +AC_DEFUN([KDE_FAST_CONFIGURE], +[ + dnl makes configure fast (needs perl) + AC_ARG_ENABLE(fast-perl, AC_HELP_STRING([--disable-fast-perl],[disable fast Makefile generation (needs perl)]), + with_fast_perl=$enableval, with_fast_perl=yes) +]) + +AC_DEFUN([KDE_CONF_FILES], +[ + val= + if test -f $srcdir/configure.files ; then + val=`sed -e 's%^%\$(top_srcdir)/%' $srcdir/configure.files` + fi + CONF_FILES= + if test -n "$val" ; then + for i in $val ; do + CONF_FILES="$CONF_FILES $i" + done + fi + AC_SUBST(CONF_FILES) +])dnl + +dnl This sets the prefix, for arts and kdelibs +dnl Do NOT use in any other module. +dnl It only looks at --prefix, KDEDIR and falls back to /usr/local/kde +AC_DEFUN([KDE_SET_PREFIX_CORE], +[ + unset CDPATH + dnl make $KDEDIR the default for the installation + AC_PREFIX_DEFAULT(${KDEDIR:-/usr/local/kde}) + + if test "x$prefix" = "xNONE"; then + prefix=$ac_default_prefix + ac_configure_args="$ac_configure_args --prefix=$prefix" + fi + # And delete superfluous '/' to make compares easier + prefix=`echo "$prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + exec_prefix=`echo "$exec_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + kde_libs_prefix='$(prefix)' + kde_libs_htmldir='$(kde_htmldir)' + AC_SUBST(kde_libs_prefix) + AC_SUBST(kde_libs_htmldir) + KDE_FAST_CONFIGURE + KDE_CONF_FILES +]) + + +AC_DEFUN([KDE_SET_PREFIX], +[ + unset CDPATH + dnl We can't give real code to that macro, only a value. + dnl It only matters for --help, since we set the prefix in this function anyway. + AC_PREFIX_DEFAULT(${KDEDIR:-the kde prefix}) + + KDE_SET_DEFAULT_BINDIRS + if test "x$prefix" = "xNONE"; then + dnl no prefix given: look for kde-config in the PATH and deduce the prefix from it + KDE_FIND_PATH(kde-config, KDECONFIG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kde-config)], [], prepend) + else + dnl prefix given: look for kde-config, preferrably in prefix, otherwise in PATH + kde_save_PATH="$PATH" + PATH="$exec_prefix/bin:$prefix/bin:$PATH" + KDE_FIND_PATH(kde-config, KDECONFIG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kde-config)], [], prepend) + PATH="$kde_save_PATH" + fi + + kde_libs_prefix=`$KDECONFIG --prefix` + if test -z "$kde_libs_prefix" || test ! -x "$kde_libs_prefix"; then + AC_MSG_ERROR([$KDECONFIG --prefix outputed the non existant prefix '$kde_libs_prefix' for kdelibs. + This means it has been moved since you installed it. + This won't work. Please recompile kdelibs for the new prefix. + ]) + fi + kde_libs_htmldir=`$KDECONFIG --install html --expandvars` + + AC_MSG_CHECKING([where to install]) + if test "x$prefix" = "xNONE"; then + prefix=$kde_libs_prefix + AC_MSG_RESULT([$prefix (as returned by kde-config)]) + else + dnl --prefix was given. Compare prefixes and warn (in configure.in.bot.end) if different + given_prefix=$prefix + AC_MSG_RESULT([$prefix (as requested)]) + fi + + # And delete superfluous '/' to make compares easier + prefix=`echo "$prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + exec_prefix=`echo "$exec_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + given_prefix=`echo "$given_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + AC_SUBST(KDECONFIG) + AC_SUBST(kde_libs_prefix) + AC_SUBST(kde_libs_htmldir) + + KDE_FAST_CONFIGURE + KDE_CONF_FILES +]) + +pushdef([AC_PROG_INSTALL], +[ + dnl our own version, testing for a -p flag + popdef([AC_PROG_INSTALL]) + dnl as AC_PROG_INSTALL works as it works we first have + dnl to save if the user didn't specify INSTALL, as the + dnl autoconf one overwrites INSTALL and we have no chance to find + dnl out afterwards + test -n "$INSTALL" && kde_save_INSTALL_given=$INSTALL + test -n "$INSTALL_PROGRAM" && kde_save_INSTALL_PROGRAM_given=$INSTALL_PROGRAM + test -n "$INSTALL_SCRIPT" && kde_save_INSTALL_SCRIPT_given=$INSTALL_SCRIPT + AC_PROG_INSTALL + + if test -z "$kde_save_INSTALL_given" ; then + # OK, user hasn't given any INSTALL, autoconf found one for us + # now we test, if it supports the -p flag + AC_MSG_CHECKING(for -p flag to install) + rm -f confinst.$$.* > /dev/null 2>&1 + echo "Testtest" > confinst.$$.orig + ac_res=no + if ${INSTALL} -p confinst.$$.orig confinst.$$.new > /dev/null 2>&1 ; then + if test -f confinst.$$.new ; then + # OK, -p seems to do no harm to install + INSTALL="${INSTALL} -p" + ac_res=yes + fi + fi + rm -f confinst.$$.* + AC_MSG_RESULT($ac_res) + fi + dnl the following tries to resolve some signs and wonders coming up + dnl with different autoconf/automake versions + dnl e.g.: + dnl *automake 1.4 install-strip sets A_M_INSTALL_PROGRAM_FLAGS to -s + dnl and has INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(A_M_INSTALL_PROGRAM_FLAGS) + dnl it header-vars.am, so there the actual INSTALL_PROGRAM gets the -s + dnl *automake 1.4a (and above) use INSTALL_STRIP_FLAG and only has + dnl INSTALL_PROGRAM = @INSTALL_PROGRAM@ there, but changes the + dnl install-@DIR@PROGRAMS targets to explicitly use that flag + dnl *autoconf 2.13 is dumb, and thinks it can use INSTALL_PROGRAM as + dnl INSTALL_SCRIPT, which breaks with automake <= 1.4 + dnl *autoconf >2.13 (since 10.Apr 1999) has not that failure + dnl *sometimes KDE does not use the install-@DIR@PROGRAM targets from + dnl automake (due to broken Makefile.am or whatever) to install programs, + dnl and so does not see the -s flag in automake > 1.4 + dnl to clean up that mess we: + dnl +set INSTALL_PROGRAM to use INSTALL_STRIP_FLAG + dnl which cleans KDE's program with automake > 1.4; + dnl +set INSTALL_SCRIPT to only use INSTALL, to clean up autoconf's problems + dnl with automake<=1.4 + dnl note that dues to this sometimes two '-s' flags are used (if KDE + dnl properly uses install-@DIR@PROGRAMS, but I don't care + dnl + dnl And to all this comes, that I even can't write in comments variable + dnl names used by automake, because it is so stupid to think I wanted to + dnl _use_ them, therefor I have written A_M_... instead of AM_ + dnl hmm, I wanted to say something ... ahh yes: Arghhh. + + if test -z "$kde_save_INSTALL_PROGRAM_given" ; then + INSTALL_PROGRAM='${INSTALL} $(INSTALL_STRIP_FLAG)' + fi + if test -z "$kde_save_INSTALL_SCRIPT_given" ; then + INSTALL_SCRIPT='${INSTALL}' + fi +])dnl + +AC_DEFUN([KDE_LANG_CPLUSPLUS], +[AC_LANG_CPLUSPLUS +ac_link='rm -rf SunWS_cache; ${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC' +pushdef([AC_LANG_CPLUSPLUS], [popdef([AC_LANG_CPLUSPLUS]) KDE_LANG_CPLUSPLUS]) +]) + +pushdef([AC_LANG_CPLUSPLUS], +[popdef([AC_LANG_CPLUSPLUS]) +KDE_LANG_CPLUSPLUS +]) + +AC_DEFUN([KDE_CHECK_LONG_LONG], +[ +AC_MSG_CHECKING(for long long) +AC_CACHE_VAL(kde_cv_c_long_long, +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_LINK([], [ + long long foo = 0; + foo = foo+1; + ], + kde_cv_c_long_long=yes, kde_cv_c_long_long=no) + AC_LANG_RESTORE +]) +AC_MSG_RESULT($kde_cv_c_long_long) +if test "$kde_cv_c_long_long" = yes; then + AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have long long as datatype]) +fi +]) + +AC_DEFUN([KDE_CHECK_LIB], +[ + kde_save_LDFLAGS="$LDFLAGS" + dnl AC_CHECK_LIB modifies LIBS, so save it here + kde_save_LIBS="$LIBS" + LDFLAGS="$LDFLAGS $all_libraries" + case $host_os in + aix*) LDFLAGS="-brtl $LDFLAGS" + test "$GCC" = yes && LDFLAGS="-Wl,$LDFLAGS" + ;; + esac + AC_CHECK_LIB($1, $2, $3, $4, $5) + LDFLAGS="$kde_save_LDFLAGS" + LIBS="$kde_save_LIBS" +]) + +AC_DEFUN([KDE_JAVA_PREFIX], +[ + dir=`dirname "$1"` + base=`basename "$1"` + list=`ls -1 $dir 2> /dev/null` + for entry in $list; do + if test -d $dir/$entry/bin; then + case $entry in + $base) + javadirs="$javadirs $dir/$entry/bin" + ;; + esac + elif test -d $dir/$entry/jre/bin; then + case $entry in + $base) + javadirs="$javadirs $dir/$entry/jre/bin" + ;; + esac + fi + done +]) + +dnl KDE_CHEC_JAVA_DIR(onlyjre) +AC_DEFUN([KDE_CHECK_JAVA_DIR], +[ + +AC_ARG_WITH(java, +AC_HELP_STRING([--with-java=javadir],[use java installed in javadir, --without-java disables]), +[ ac_java_dir=$withval +], ac_java_dir="" +) + +AC_MSG_CHECKING([for Java]) + +dnl at this point ac_java_dir is either a dir, 'no' to disable, or '' to say look in $PATH +if test "x$ac_java_dir" = "xno"; then + kde_java_bindir=no + kde_java_includedir=no + kde_java_libjvmdir=no + kde_java_libgcjdir=no + kde_java_libhpidir=no +else + if test "x$ac_java_dir" = "x"; then + + + dnl No option set -> collect list of candidate paths + if test -n "$JAVA_HOME"; then + KDE_JAVA_PREFIX($JAVA_HOME) + fi + KDE_JAVA_PREFIX(/usr/j2se) + KDE_JAVA_PREFIX(/usr/lib/j2se) + KDE_JAVA_PREFIX(/usr/j*dk*) + KDE_JAVA_PREFIX(/usr/lib/j*dk*) + KDE_JAVA_PREFIX(/opt/j*sdk*) + KDE_JAVA_PREFIX(/usr/lib/java*) + KDE_JAVA_PREFIX(/usr/java*) + KDE_JAVA_PREFIX(/usr/java/j*dk*) + KDE_JAVA_PREFIX(/usr/java/j*re*) + KDE_JAVA_PREFIX(/usr/lib/SunJava2*) + KDE_JAVA_PREFIX(/usr/lib/SunJava*) + KDE_JAVA_PREFIX(/usr/lib/IBMJava2*) + KDE_JAVA_PREFIX(/usr/lib/IBMJava*) + KDE_JAVA_PREFIX(/opt/java*) + + kde_cv_path="NONE" + kde_save_IFS=$IFS + IFS=':' + for dir in $PATH; do + if test -d "$dir"; then + javadirs="$javadirs $dir" + fi + done + IFS=$kde_save_IFS + jredirs= + + dnl Now javadirs contains a list of paths that exist, all ending with bin/ + for dir in $javadirs; do + dnl Check for the java executable + if test -x "$dir/java"; then + sane_path=$(cd $dir; /bin/pwd) + dnl And also check for a libjvm.so somewhere under there + dnl Since we have to go to the parent dir, /usr/bin is excluded, /usr is too big. + if test "$sane_path" != "/usr/bin"; then + libjvmdir=`find $dir/.. -name libjvm.so | sed 's,libjvm.so,,'|head -n 1` + if test ! -f $libjvmdir/libjvm.so; then continue; fi + jredirs="$jredirs $dir" + fi + fi + done + + dnl Now jredirs contains a reduced list, of paths where both java and ../**/libjvm.so was found + JAVAC= + JAVA= + kde_java_bindir=no + for dir in $jredirs; do + JAVA="$dir/java" + kde_java_bindir=$dir + if test -x "$dir/javac"; then + JAVAC="$dir/javac" + break + fi + done + + if test -n "$JAVAC"; then + dnl this substitution might not work - well, we test for jni.h below + kde_java_includedir=`echo $JAVAC | sed -e 's,bin/javac$,include/,'` + else + kde_java_includedir=no + fi + else + dnl config option set + kde_java_bindir=$ac_java_dir/bin + if test -x $ac_java_dir/bin/java && test ! -x $ac_java_dir/bin/javac; then + kde_java_includedir=no + else + kde_java_includedir=$ac_java_dir/include + fi + fi +fi + +dnl At this point kde_java_bindir and kde_java_includedir are either set or "no" +if test "x$kde_java_bindir" != "xno"; then + + dnl Look for libjvm.so + kde_java_libjvmdir=`find $kde_java_bindir/.. -name libjvm.so | sed 's,libjvm.so,,'|head -n 1` + dnl Look for libgcj.so + kde_java_libgcjdir=`find $kde_java_bindir/.. -name libgcj.so | sed 's,libgcj.so,,'|head -n 1` + dnl Look for libhpi.so and avoid green threads + kde_java_libhpidir=`find $kde_java_bindir/.. -name libhpi.so | grep -v green | sed 's,libhpi.so,,' | head -n 1` + + dnl Now check everything's fine under there + dnl the include dir is our flag for having the JDK + if test -d "$kde_java_includedir"; then + if test ! -x "$kde_java_bindir/javac"; then + AC_MSG_ERROR([javac not found under $kde_java_bindir - it seems you passed a wrong --with-java.]) + fi + if test ! -x "$kde_java_bindir/javah"; then + AC_MSG_ERROR([javah not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + if test ! -x "$kde_java_bindir/jar"; then + AC_MSG_ERROR([jar not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + if test ! -r "$kde_java_includedir/jni.h"; then + AC_MSG_ERROR([jni.h not found under $kde_java_includedir. Use --with-java or --without-java.]) + fi + + jni_includes="-I$kde_java_includedir" + dnl Strange thing, jni.h requires jni_md.h which is under genunix here.. + dnl and under linux here.. + + dnl not needed for gcj + + if test "x$kde_java_libgcjdir" = "x"; then + test -d "$kde_java_includedir/linux" && jni_includes="$jni_includes -I$kde_java_includedir/linux" + test -d "$kde_java_includedir/solaris" && jni_includes="$jni_includes -I$kde_java_includedir/solaris" + test -d "$kde_java_includedir/genunix" && jni_includes="$jni_includes -I$kde_java_includedir/genunix" + fi + + else + JAVAC= + jni_includes= + fi + + if test "x$kde_java_libgcjdir" = "x"; then + if test ! -r "$kde_java_libjvmdir/libjvm.so"; then + AC_MSG_ERROR([libjvm.so not found under $kde_java_libjvmdir. Use --without-java.]) + fi + else + if test ! -r "$kde_java_libgcjdir/libgcj.so"; then + AC_MSG_ERROR([libgcj.so not found under $kde_java_libgcjdir. Use --without-java.]) + fi + fi + + if test ! -x "$kde_java_bindir/java"; then + AC_MSG_ERROR([java not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + + dnl not needed for gcj compile + + if test "x$kde_java_libgcjdir" = "x"; then + if test ! -r "$kde_java_libhpidir/libhpi.so"; then + AC_MSG_ERROR([libhpi.so not found under $kde_java_libhpidir. Use --without-java.]) + fi + fi + + if test -n "$jni_includes"; then + dnl Check for JNI version + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_cxxflags_safe="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $all_includes $jni_includes" + + AC_TRY_COMPILE([ + #include + ], + [ + #ifndef JNI_VERSION_1_2 + Syntax Error + #endif + ],[ kde_jni_works=yes ], + [ kde_jni_works=no ]) + + if test $kde_jni_works = no; then + AC_MSG_ERROR([Incorrect version of $kde_java_includedir/jni.h. + You need to have Java Development Kit (JDK) version 1.2. + + Use --with-java to specify another location. + Use --without-java to configure without java support. + Or download a newer JDK and try again. + See e.g. http://java.sun.com/products/jdk/1.2 ]) + fi + + CXXFLAGS="$ac_cxxflags_safe" + AC_LANG_RESTORE + + dnl All tests ok, inform and subst the variables + + JAVAC=$kde_java_bindir/javac + JAVAH=$kde_java_bindir/javah + JAR=$kde_java_bindir/jar + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + if test "x$kde_java_libgcjdir" = "x"; then + JVMLIBS="-L$kde_java_libjvmdir -ljvm -L$kde_java_libhpidir -lhpi" + else + JVMLIBS="-L$kde_java_libgcjdir -lgcj" + fi + AC_MSG_RESULT([java JDK in $kde_java_bindir]) + + else + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + AC_MSG_RESULT([java JRE in $kde_java_bindir]) + fi +elif test -d "/Library/Java/Home"; then + kde_java_bindir="/Library/Java/Home/bin" + jni_includes="-I/Library/Java/Home/include" + + JAVAC=$kde_java_bindir/javac + JAVAH=$kde_java_bindir/javah + JAR=$kde_java_bindir/jar + JVMLIBS="-Wl,-framework,JavaVM" + + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + AC_MSG_RESULT([Apple Java Framework]) +else + AC_MSG_RESULT([none found]) +fi + +AC_SUBST(JAVAC) +AC_SUBST(JAVAH) +AC_SUBST(JAR) +AC_SUBST(JVMLIBS) +AC_SUBST(jni_includes) + +# for backward compat +kde_cv_java_includedir=$kde_java_includedir +kde_cv_java_bindir=$kde_java_bindir +]) + +dnl this is a redefinition of autoconf 2.5x's AC_FOREACH. +dnl When the argument list becomes big, as in KDE for AC_OUTPUT in +dnl big packages, m4_foreach is dog-slow. So use our own version of +dnl it. (matz@kde.org) +m4_define([mm_foreach], +[m4_pushdef([$1])_mm_foreach($@)m4_popdef([$1])]) +m4_define([mm_car], [[$1]]) +m4_define([mm_car2], [[$@]]) +m4_define([_mm_foreach], +[m4_if(m4_quote($2), [], [], + [m4_define([$1], mm_car($2))$3[]_mm_foreach([$1], + mm_car2(m4_shift($2)), + [$3])])]) +m4_define([AC_FOREACH], +[mm_foreach([$1], m4_split(m4_normalize([$2])), [$3])]) + +AC_DEFUN([KDE_NEED_FLEX], +[ +kde_libs_safe=$LIBS +LIBS="$LIBS $USER_LDFLAGS" +AM_PROG_LEX +LIBS=$kde_libs_safe +if test -z "$LEXLIB"; then + AC_MSG_ERROR([You need to have flex installed.]) +fi +AC_SUBST(LEXLIB) +]) + +AC_DEFUN([AC_PATH_QTOPIA], +[ + dnl TODO: use AC_CACHE_VAL + + if test -z "$1"; then + qtopia_minver_maj=1 + qtopia_minver_min=5 + qtopia_minver_pat=0 + else + qtopia_minver_maj=`echo "$1" | sed -e "s/^\(.*\)\..*\..*$/\1/"` + qtopia_minver_min=`echo "$1" | sed -e "s/^.*\.\(.*\)\..*$/\1/"` + qtopia_minver_pat=`echo "$1" | sed -e "s/^.*\..*\.\(.*\)$/\1/"` + fi + + qtopia_minver="$qtopia_minver_maj$qtopia_minver_min$qtopia_minver_pat" + qtopia_minverstr="$qtopia_minver_maj.$qtopia_minver_min.$qtopia_minver_pat" + + AC_REQUIRE([AC_PATH_QT]) + + AC_MSG_CHECKING([for Qtopia]) + + LIB_QTOPIA="-lqpe" + AC_SUBST(LIB_QTOPIA) + + kde_qtopia_dirs="$QPEDIR /opt/Qtopia" + + ac_qtopia_incdir=NO + + AC_ARG_WITH(qtopia-dir, + AC_HELP_STRING([--with-qtopia-dir=DIR],[where the root of Qtopia is installed]), + [ ac_qtopia_incdir="$withval"/include] ) + + qtopia_incdirs="" + for dir in $kde_qtopia_dirs; do + qtopia_incdirs="$qtopia_incdirs $dir/include" + done + + if test ! "$ac_qtopia_incdir" = "NO"; then + qtopia_incdirs="$ac_qtopia_incdir $qtopia_incdirs" + fi + + qtopia_incdir="" + AC_FIND_FILE(qpe/qpeapplication.h, $qtopia_incdirs, qtopia_incdir) + ac_qtopia_incdir="$qtopia_incdir" + + if test -z "$qtopia_incdir"; then + AC_MSG_ERROR([Cannot find Qtopia headers. Please check your installation.]) + fi + + qtopia_ver_maj=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION "\(.*\)\..*\..*".*,\1,p'`; + qtopia_ver_min=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION ".*\.\(.*\)\..*".*,\1,p'`; + qtopia_ver_pat=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION ".*\..*\.\(.*\)".*,\1,p'`; + + qtopia_ver="$qtopia_ver_maj$qtopia_ver_min$qtopia_ver_pat" + qtopia_verstr="$qtopia_ver_maj.$qtopia_ver_min.$qtopia_ver_pat" + if test "$qtopia_ver" -lt "$qtopia_minver"; then + AC_MSG_ERROR([found Qtopia version $qtopia_verstr but version $qtopia_minverstr +is required.]) + fi + + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + ac_cxxflags_safe="$CXXFLAGS" + ac_ldflags_safe="$LDFLAGS" + ac_libs_safe="$LIBS" + + CXXFLAGS="$CXXFLAGS -I$qtopia_incdir $all_includes" + LDFLAGS="$LDFLAGS $QT_LDFLAGS $all_libraries $USER_LDFLAGS $KDE_MT_LDFLAGS" + LIBS="$LIBS $LIB_QTOPIA $LIBQT" + + cat > conftest.$ac_ext < +#include + +int main( int argc, char **argv ) +{ + QPEApplication app( argc, argv ); + return 0; +} +EOF + + if AC_TRY_EVAL(ac_link) && test -s conftest; then + rm -f conftest* + else + rm -f conftest* + AC_MSG_ERROR([Cannot link small Qtopia Application. For more details look at +the end of config.log]) + fi + + CXXFLAGS="$ac_cxxflags_safe" + LDFLAGS="$ac_ldflags_safe" + LIBS="$ac_libs_safe" + + AC_LANG_RESTORE + + QTOPIA_INCLUDES="-I$qtopia_incdir" + AC_SUBST(QTOPIA_INCLUDES) + + AC_MSG_RESULT([found version $qtopia_verstr with headers at $qtopia_incdir]) +]) + + +AC_DEFUN([KDE_INIT_DOXYGEN], +[ +AC_MSG_CHECKING([for Qt docs]) +kde_qtdir= +if test "${with_qt_dir+set}" = set; then + kde_qtdir="$with_qt_dir" +fi + +AC_FIND_FILE(qsql.html, [ $kde_qtdir/doc/html $QTDIR/doc/html /usr/share/doc/packages/qt3/html /usr/lib/qt/doc /usr/lib/qt3/doc /usr/lib/qt3/doc/html /usr/doc/qt3/html /usr/doc/qt3 /usr/share/doc/qt3-doc /usr/share/qt3/doc/html /usr/X11R6/share/doc/qt/html ], QTDOCDIR) +AC_MSG_RESULT($QTDOCDIR) + +AC_SUBST(QTDOCDIR) + +KDE_FIND_PATH(dot, DOT, [], []) +if test -n "$DOT"; then + KDE_HAVE_DOT="YES" +else + KDE_HAVE_DOT="NO" +fi +AC_SUBST(KDE_HAVE_DOT) +KDE_FIND_PATH(doxygen, DOXYGEN, [], []) +AC_SUBST(DOXYGEN) + +DOXYGEN_PROJECT_NAME="$1" +DOXYGEN_PROJECT_NUMBER="$2" +AC_SUBST(DOXYGEN_PROJECT_NAME) +AC_SUBST(DOXYGEN_PROJECT_NUMBER) + +KDE_HAS_DOXYGEN=no +if test -n "$DOXYGEN" && test -x "$DOXYGEN" && test -f $QTDOCDIR/qsql.html; then + KDE_HAS_DOXYGEN=yes +fi +AC_SUBST(KDE_HAS_DOXYGEN) + +]) + + +AC_DEFUN([AC_FIND_BZIP2], +[ +AC_MSG_CHECKING([for bzDecompress in libbz2]) +AC_CACHE_VAL(ac_cv_lib_bzip2, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -lbz2 $LIBSOCKET" +kde_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK(dnl +[ +#define BZ_NO_STDIO +#include +], + [ bz_stream s; (void) bzDecompress(&s); ], + eval "ac_cv_lib_bzip2='-lbz2'", + eval "ac_cv_lib_bzip2=no") +LIBS="$kde_save_LIBS" +CXXFLAGS="$kde_save_CXXFLAGS" +AC_LANG_RESTORE +])dnl +AC_MSG_RESULT($ac_cv_lib_bzip2) + +if test ! "$ac_cv_lib_bzip2" = no; then + BZIP2DIR=bzip2 + + LIBBZ2="$ac_cv_lib_bzip2" + AC_SUBST(LIBBZ2) + +else + + cxx_shared_flag= + ld_shared_flag= + KDE_CHECK_COMPILER_FLAG(shared, [ + ld_shared_flag="-shared" + ]) + KDE_CHECK_COMPILER_FLAG(fPIC, [ + cxx_shared_flag="-fPIC" + ]) + + AC_MSG_CHECKING([for BZ2_bzDecompress in (shared) libbz2]) + AC_CACHE_VAL(ac_cv_lib_bzip2_prefix, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + kde_save_LIBS="$LIBS" + LIBS="$all_libraries $USER_LDFLAGS $ld_shared_flag -lbz2 $LIBSOCKET" + kde_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CFLAGS $cxx_shared_flag $all_includes $USER_INCLUDES" + + AC_TRY_LINK(dnl + [ + #define BZ_NO_STDIO + #include + ], + [ bz_stream s; (void) BZ2_bzDecompress(&s); ], + eval "ac_cv_lib_bzip2_prefix='-lbz2'", + eval "ac_cv_lib_bzip2_prefix=no") + LIBS="$kde_save_LIBS" + CXXFLAGS="$kde_save_CXXFLAGS" + AC_LANG_RESTORE + ])dnl + + AC_MSG_RESULT($ac_cv_lib_bzip2_prefix) + + if test ! "$ac_cv_lib_bzip2_prefix" = no; then + BZIP2DIR=bzip2 + + LIBBZ2="$ac_cv_lib_bzip2_prefix" + AC_SUBST(LIBBZ2) + + AC_DEFINE(NEED_BZ2_PREFIX, 1, [Define if the libbz2 functions need the BZ2_ prefix]) + dnl else, we just ignore this + fi + +fi +AM_CONDITIONAL(include_BZIP2, test -n "$BZIP2DIR") +]) + +dnl ------------------------------------------------------------------------ +dnl Try to find the SSL headers and libraries. +dnl $(SSL_LDFLAGS) will be -Lsslliblocation (if needed) +dnl and $(SSL_INCLUDES) will be -Isslhdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([KDE_CHECK_SSL], +[ +LIBSSL="-lssl -lcrypto" +AC_REQUIRE([KDE_CHECK_LIB64]) + +ac_ssl_includes=NO ac_ssl_libraries=NO +ssl_libraries="" +ssl_includes="" +AC_ARG_WITH(ssl-dir, + AC_HELP_STRING([--with-ssl-dir=DIR],[where the root of OpenSSL is installed]), + [ ac_ssl_includes="$withval"/include + ac_ssl_libraries="$withval"/lib$kdelibsuff + ]) + +want_ssl=yes +AC_ARG_WITH(ssl, + AC_HELP_STRING([--without-ssl],[disable SSL checks]), + [want_ssl=$withval]) + +if test $want_ssl = yes; then + +AC_MSG_CHECKING(for OpenSSL) + +AC_CACHE_VAL(ac_cv_have_ssl, +[#try to guess OpenSSL locations + + ssl_incdirs="/usr/include /usr/local/include /usr/ssl/include /usr/local/ssl/include $prefix/include $kde_extra_includes" + ssl_incdirs="$ac_ssl_includes $ssl_incdirs" + AC_FIND_FILE(openssl/ssl.h, $ssl_incdirs, ssl_incdir) + ac_ssl_includes="$ssl_incdir" + + ssl_libdirs="/usr/lib$kdelibsuff /usr/local/lib$kdelibsuff /usr/ssl/lib$kdelibsuff /usr/local/ssl/lib$kdelibsuff $libdir $prefix/lib$kdelibsuff $exec_prefix/lib$kdelibsuff $kde_extra_libs" + if test ! "$ac_ssl_libraries" = "NO"; then + ssl_libdirs="$ac_ssl_libraries $ssl_libdirs" + fi + + test=NONE + ssl_libdir=NONE + for dir in $ssl_libdirs; do + try="ls -1 $dir/libssl*" + if test=`eval $try 2> /dev/null`; then ssl_libdir=$dir; break; else echo "tried $dir" >&AC_FD_CC ; fi + done + + ac_ssl_libraries="$ssl_libdir" + + ac_ldflags_safe="$LDFLAGS" + ac_libs_safe="$LIBS" + + LDFLAGS="$LDFLAGS -L$ssl_libdir $all_libraries" + LIBS="$LIBS $LIBSSL -lRSAglue -lrsaref" + + AC_TRY_LINK(,void RSAPrivateEncrypt(void);RSAPrivateEncrypt();, + ac_ssl_rsaref="yes" + , + ac_ssl_rsaref="no" + ) + + LDFLAGS="$ac_ldflags_safe" + LIBS="$ac_libs_safe" + + if test "$ac_ssl_includes" = NO || test "$ac_ssl_libraries" = NO; then + have_ssl=no + else + have_ssl=yes; + fi + + ]) + + eval "$ac_cv_have_ssl" + + AC_MSG_RESULT([libraries $ac_ssl_libraries, headers $ac_ssl_includes]) + + AC_MSG_CHECKING([whether OpenSSL uses rsaref]) + AC_MSG_RESULT($ac_ssl_rsaref) + + AC_MSG_CHECKING([for easter eggs]) + AC_MSG_RESULT([none found]) + +else + have_ssl=no +fi + +if test "$have_ssl" = yes; then + AC_MSG_CHECKING(for OpenSSL version) + dnl Check for SSL version + AC_CACHE_VAL(ac_cv_ssl_version, + [ + + cat >conftest.$ac_ext < +#include + int main() { + +#ifndef OPENSSL_VERSION_NUMBER + printf("ssl_version=\\"error\\"\n"); +#else + if (OPENSSL_VERSION_NUMBER < 0x00906000) + printf("ssl_version=\\"old\\"\n"); + else + printf("ssl_version=\\"ok\\"\n"); +#endif + return (0); + } +EOF + + ac_save_CPPFLAGS=$CPPFLAGS + if test "$ac_ssl_includes" != "/usr/include"; then + CPPFLAGS="$CPPFLAGS -I$ac_ssl_includes" + fi + + if AC_TRY_EVAL(ac_link); then + + if eval `./conftest 2>&5`; then + if test $ssl_version = error; then + AC_MSG_ERROR([$ssl_incdir/openssl/opensslv.h doesn't define OPENSSL_VERSION_NUMBER !]) + else + if test $ssl_version = old; then + AC_MSG_WARN([OpenSSL version too old. Upgrade to 0.9.6 at least, see http://www.openssl.org. SSL support disabled.]) + have_ssl=no + fi + fi + ac_cv_ssl_version="ssl_version=$ssl_version" + else + AC_MSG_ERROR([Your system couldn't run a small SSL test program. + Check config.log, and if you can't figure it out, send a mail to + David Faure , attaching your config.log]) + fi + + else + AC_MSG_ERROR([Your system couldn't link a small SSL test program. + Check config.log, and if you can't figure it out, send a mail to + David Faure , attaching your config.log]) + fi + CPPFLAGS=$ac_save_CPPFLAGS + + ]) + + eval "$ac_cv_ssl_version" + AC_MSG_RESULT($ssl_version) +fi + +if test "$have_ssl" != yes; then + LIBSSL=""; +else + AC_DEFINE(HAVE_SSL, 1, [If we are going to use OpenSSL]) + ac_cv_have_ssl="have_ssl=yes \ + ac_ssl_includes=$ac_ssl_includes ac_ssl_libraries=$ac_ssl_libraries ac_ssl_rsaref=$ac_ssl_rsaref" + + + ssl_libraries="$ac_ssl_libraries" + ssl_includes="$ac_ssl_includes" + + if test "$ac_ssl_rsaref" = yes; then + LIBSSL="-lssl -lcrypto -lRSAglue -lrsaref" + fi + + if test $ssl_version = "old"; then + AC_DEFINE(HAVE_OLD_SSL_API, 1, [Define if you have OpenSSL < 0.9.6]) + fi +fi + +SSL_INCLUDES= + +if test "$ssl_includes" = "/usr/include"; then + if test -f /usr/kerberos/include/krb5.h; then + SSL_INCLUDES="-I/usr/kerberos/include" + fi +elif test "$ssl_includes" != "/usr/local/include" && test -n "$ssl_includes"; then + SSL_INCLUDES="-I$ssl_includes" +fi + +if test "$ssl_libraries" = "/usr/lib" || test "$ssl_libraries" = "/usr/local/lib" || test -z "$ssl_libraries" || test "$ssl_libraries" = "NONE"; then + SSL_LDFLAGS="" +else + SSL_LDFLAGS="-L$ssl_libraries -R$ssl_libraries" +fi + +AC_SUBST(SSL_INCLUDES) +AC_SUBST(SSL_LDFLAGS) +AC_SUBST(LIBSSL) +]) + +AC_DEFUN([KDE_CHECK_STRLCPY], +[ + AC_REQUIRE([AC_CHECK_STRLCAT]) + AC_REQUIRE([AC_CHECK_STRLCPY]) + AC_CHECK_SIZEOF(size_t) + AC_CHECK_SIZEOF(unsigned long) + + AC_MSG_CHECKING([sizeof size_t == sizeof unsigned long]) + AC_TRY_COMPILE(,[ + #if SIZEOF_SIZE_T != SIZEOF_UNSIGNED_LONG + choke me + #endif + ],AC_MSG_RESULT([yes]),[ + AC_MSG_RESULT(no) + AC_MSG_ERROR([ + Apparently on your system our assumption sizeof size_t == sizeof unsigned long + does not apply. Please mail kde-devel@kde.org with a description of your system! + ]) + ]) +]) + +AC_DEFUN([KDE_CHECK_BINUTILS], +[ + AC_MSG_CHECKING([if ld supports unversioned version maps]) + + kde_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map" + echo "{ local: extern \"C++\" { foo }; };" > conftest.map + AC_TRY_LINK([int foo;], +[ +#ifdef __INTEL_COMPILER +icc apparently does not support libtools version-info and version-script +at the same time. Dunno where the bug is, but until somebody figured out, +better disable the optional version scripts. +#endif + + foo = 42; +], kde_supports_versionmaps=yes, kde_supports_versionmaps=no) + LDFLAGS="$kde_save_LDFLAGS" + rm -f conftest.map + AM_CONDITIONAL(include_VERSION_SCRIPT, + [test "$kde_supports_versionmaps" = "yes" && test "$kde_use_debug_code" = "no"]) + + AC_MSG_RESULT($kde_supports_versionmaps) +]) + +AC_DEFUN([AM_PROG_OBJC],[ +AC_CHECK_PROGS(OBJC, gcc, gcc) +test -z "$OBJC" && AC_MSG_ERROR([no acceptable objective-c gcc found in \$PATH]) +if test "x${OBJCFLAGS-unset}" = xunset; then + OBJCFLAGS="-g -O2" +fi +AC_SUBST(OBJCFLAGS) +_AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES(OBJC)]) +]) + +AC_DEFUN([KDE_CHECK_PERL], +[ + KDE_FIND_PATH(perl, PERL, [$bindir $exec_prefix/bin $prefix/bin], [ + AC_MSG_ERROR([No Perl found in your $PATH. +We need perl to generate some code.]) + ]) + AC_SUBST(PERL) +]) + +AC_DEFUN([KDE_CHECK_LARGEFILE], +[ +AC_SYS_LARGEFILE +if test "$ac_cv_sys_file_offset_bits" != no; then + CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits" +fi + +if test "x$ac_cv_sys_large_files" != "xno"; then + CPPFLAGS="$CPPFLAGS -D_LARGE_FILES=1" +fi + +]) + +dnl A small extension to PKG_CHECK_MODULES (defined in pkg.m4.in) +dnl which allows to search for libs that get installed into the KDE prefix. +dnl +dnl Syntax: KDE_PKG_CHECK_MODULES(KSTUFF, libkexif >= 0.2 glib = 1.3.4, action-if, action-not) +dnl defines KSTUFF_LIBS, KSTUFF_CFLAGS, see pkg-config man page +dnl also defines KSTUFF_PKG_ERRORS on error +AC_DEFUN([KDE_PKG_CHECK_MODULES], [ + + PKG_CONFIG_PATH="$prefix/lib${kdelibsuff}/pkgconfig:$PKG_CONFIG_PATH" + if test "$prefix" != "$kde_libs_prefix"; then + PKG_CONFIG_PATH="$kde_libs_prefix/lib${kdelibsuff}/pkgconfig:$PKG_CONFIG_PATH" + fi + export PKG_CONFIG_PATH + PKG_CHECK_MODULES([$1],[$2],[$3],[$4]) +]) + + +dnl Check for PIE support in the compiler and linker +AC_DEFUN([KDE_CHECK_PIE_SUPPORT], +[ + AC_CACHE_CHECK([for PIE support], kde_cv_val_pie_support, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + safe_CXXFLAGS=$CXXFLAGS + safe_LDFLAGS=$LDFLAGS + CXXFLAGS="$CXXFLAGS -fPIE" + LDFLAGS="$LDFLAGS -pie" + + AC_TRY_LINK([int foo;], [], [kde_cv_val_pie_support=yes], [kde_cv_val_pie_support=no]) + + CXXFLAGS=$safe_CXXFLAGS + LDFLAGS=$safe_LDFLAGS + AC_LANG_RESTORE + ]) + + AC_MSG_CHECKING(if enabling -pie/fPIE support) + + AC_ARG_ENABLE(pie, + AC_HELP_STRING([--enable-pie],[platform supports PIE linking [default=detect]]), + [kde_has_pie_support=$enableval], + [kde_has_pie_support=detect]) + + if test "$kde_has_pie_support" = "detect"; then + kde_has_pie_support=$kde_cv_val_pie_support + fi + + AC_MSG_RESULT([$kde_has_pie_support]) + + KDE_USE_FPIE="" + KDE_USE_PIE="" + + AC_SUBST([KDE_USE_FPIE]) + AC_SUBST([KDE_USE_PIE]) + + if test "$kde_has_pie_support" = "yes"; then + KDE_USE_FPIE="-fPIE" + KDE_USE_PIE="-pie" + fi +]) +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +## Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 +## Free Software Foundation, Inc. +## Originally by Gordon Matzigkeit , 1996 +## +## This file is free software; the Free Software Foundation gives +## unlimited permission to copy and/or distribute it, with or without +## modifications, as long as this notice is preserved. + +# serial 48 Debian 1.5.22-4 AC_PROG_LIBTOOL + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +AC_DEFUN([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +AC_DEFUN([_LT_COMPILER_BOILERPLATE], +[ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +AC_DEFUN([_LT_LINKER_BOILERPLATE], +[ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_LINKER_BOILERPLATE + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string=`eval $cmd`) 2>/dev/null && + echo_test_string=`eval $cmd` && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) LD="${LD-ld} -64" ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# ------------------ +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# --------------------------------------------------------------------- +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ---------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + if test -z "$LTCFLAGS"; then + eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 DLLs +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +# set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix3*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# it is assumed to be `libltdl'. LIBLTDL will be prefixed with +# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/' +# (note the single quotes!). If your package is not flat and you're not +# using automake, define top_builddir and top_srcdir appropriately in +# the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# and an installed libltdl is not found, it is assumed to be `libltdl'. +# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and top_srcdir +# appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + +# _LT_AC_PROG_CXXCPP +# ------------------ +AC_DEFUN([_LT_AC_PROG_CXXCPP], +[ +AC_REQUIRE([AC_PROG_CXX]) +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +fi +])# _LT_AC_PROG_CXXCPP + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# ------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF + +# Report which library types will actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + $as_unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + $as_unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes ; then + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + ;; + *) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + interix3*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc*) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC*) + # Portland Group C++ compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + ;; + osf3*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. We must also pass each convience library through + # to the system linker between allextract/defaultextract. + # The C++ compiler will combine linker options so we + # cannot just pass the convience library names through + # without $wl. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + # So that behaviour is only enabled if SCOABSPATH is set to a + # non-empty value in the environment. Most likely only useful for + # creating official distributions of packages. + # This is a hack until libtool officially supports absolute path + # names for shared libraries. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the 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. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux* | k*bsd*-gnu) + if test "$host_cpu" = ia64; then + symcode='[[ABCDGIRSTW]]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC*) + # Portland Group C++ compiler. + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\" +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + linux* | k*bsd*-gnu) + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + _LT_CC_BASENAME([$compiler]) + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix3*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi[[45]]*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' + _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine linker options so we + # cannot just pass the convience library names through + # without $wl, iff we do not link with $LD. + # Luckily, gcc supports the same syntax we need for Sun Studio. + # Supported since Solaris 2.6 (maybe 2.5.1?) + case $wlarc in + '') + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; + *) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; + esac ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_MSG_RESULT([$SED]) +]) + +dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) +dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page +dnl also defines GSTUFF_PKG_ERRORS on error +AC_DEFUN([PKG_CHECK_MODULES], [ + succeeded=no + + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + if test "$PKG_CONFIG" = "no" ; then + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + PKG_CONFIG_MIN_VERSION=0.9.0 + if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then + AC_MSG_CHECKING(for $2) + + if $PKG_CONFIG --exists "$2" ; then + AC_MSG_RESULT(yes) + succeeded=yes + + AC_MSG_CHECKING($1_CFLAGS) + $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` + AC_MSG_RESULT($$1_CFLAGS) + + AC_MSG_CHECKING($1_LIBS) + $1_LIBS=`$PKG_CONFIG --libs "$2"` + AC_MSG_RESULT($$1_LIBS) + else + $1_CFLAGS="" + $1_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + ifelse([$4], ,echo $$1_PKG_ERRORS,) + fi + + AC_SUBST($1_CFLAGS) + AC_SUBST($1_LIBS) + else + echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." + echo "*** See http://www.freedesktop.org/software/pkgconfig" + fi + fi + + if test $succeeded = yes; then + ifelse([$3], , :, [$3]) + else + ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) + fi +]) + + diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..b32a919 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,913 @@ +# generated automatically by aclocal 1.9.6 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.9.6])]) + +# Figure out how to run the assembler. -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_PROG_AS +# ---------- +AC_DEFUN([AM_PROG_AS], +[# By default we simply use the C compiler to build assembly code. +AC_REQUIRE([AC_PROG_CC]) +test "${CCAS+set}" = set || CCAS=$CC +test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS +AC_ARG_VAR([CCAS], [assembler compiler command (defaults to CC)]) +AC_ARG_VAR([CCASFLAGS], [assembler compiler flags (defaults to CFLAGS)]) +]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 7 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 12 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.58])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +AC_DEFUN([AM_MAINTAINER_MODE], +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST(MAINT)dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. +# +# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories +# created by `make install' are always world readable, even if the +# installer happens to have an overly restrictive umask (e.g. 077). +# This was a mistake. There are at least two reasons why we must not +# use `-m 0755': +# - it causes special bits like SGID to be ignored, +# - it may be too restrictive (some setups expect 775 directories). +# +# Do not use -m 0755 and let people choose whatever they expect by +# setting umask. +# +# We cannot accept any implementation of `mkdir' that recognizes `-p'. +# Some implementations (such as Solaris 8's) are not thread-safe: if a +# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' +# concurrently, both version can detect that a/ is missing, but only +# one can create it and the other will error out. Consequently we +# restrict ourselves to GNU make (using the --version option ensures +# this.) +AC_DEFUN([AM_PROG_MKDIR_P], +[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi +AC_SUBST([mkdir_p])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([acinclude.m4]) diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..0f2bd4a --- /dev/null +++ b/config.h.in @@ -0,0 +1,273 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* If we have libkipi installed */ +#undef GV_HAVE_KIPI + +/* Define to 1 if you have Xcursor */ +#undef GV_HAVE_XCURSOR + +/* Define to 1 if you have the header file. */ +#undef HAVE_CARBON_CARBON_H + +/* Define if you have the CoreAudio API */ +#undef HAVE_COREAUDIO + +/* Define to 1 if you have the header file. */ +#undef HAVE_CRT_EXTERNS_H + +/* Defines if your system has the crypt function */ +#undef HAVE_CRYPT + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_EXIV2_IMAGE_HPP + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define if you have libjpeg */ +#undef HAVE_LIBJPEG + +/* Define if you have libmng */ +#undef HAVE_LIBMNG + +/* Define if you have libpng */ +#undef HAVE_LIBPNG + +/* Define if you have a working libpthread (will enable threaded code) */ +#undef HAVE_LIBPTHREAD + +/* Define if you have libz */ +#undef HAVE_LIBZ + +/* Define if you have lround */ +#undef HAVE_LROUND + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define if your system needs _NSGetEnviron to set up the environment */ +#undef HAVE_NSGETENVIRON + +/* Define to 1 if the assembler supports AltiVec instructions. */ +#undef HAVE_PPC_ALTIVEC + +/* Define if you have res_init */ +#undef HAVE_RES_INIT + +/* Define if you have the res_init prototype */ +#undef HAVE_RES_INIT_PROTO + +/* Define if you have a STL implementation by SGI */ +#undef HAVE_SGI_STL + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have strlcat */ +#undef HAVE_STRLCAT + +/* Define if you have the strlcat prototype */ +#undef HAVE_STRLCAT_PROTO + +/* Define if you have strlcpy */ +#undef HAVE_STRLCPY + +/* Define if you have the strlcpy prototype */ +#undef HAVE_STRLCPY_PROTO + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_BITYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_X11_XCURSOR_XCURSOR_H + +/* Define to 1 if the assembler supports 3DNOW instructions. */ +#undef HAVE_X86_3DNOW + +/* Define to 1 if the assembler supports MMX instructions. */ +#undef HAVE_X86_MMX + +/* Define to 1 if the assembler supports SSE instructions. */ +#undef HAVE_X86_SSE + +/* Define to 1 if the assembler supports SSE2 instructions. */ +#undef HAVE_X86_SSE2 + +/* Suffix for lib directories */ +#undef KDELIBSUFF + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of `char *', as computed by sizeof. */ +#undef SIZEOF_CHAR_P + +/* The size of `int', as computed by sizeof. */ +#undef SIZEOF_INT + +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `short', as computed by sizeof. */ +#undef SIZEOF_SHORT + +/* The size of `size_t', as computed by sizeof. */ +#undef SIZEOF_SIZE_T + +/* The size of `unsigned long', as computed by sizeof. */ +#undef SIZEOF_UNSIGNED_LONG + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Defined if compiling without arts */ +#undef WITHOUT_ARTS + +/* + * jpeg.h needs HAVE_BOOLEAN, when the system uses boolean in system + * headers and I'm too lazy to write a configure test as long as only + * unixware is related + */ +#ifdef _UNIXWARE +#define HAVE_BOOLEAN +#endif + + + +/* + * AIX defines FD_SET in terms of bzero, but fails to include + * that defines bzero. + */ + +#if defined(_AIX) +#include +#endif + + + +#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +# include +# include +# define environ (*_NSGetEnviron()) +#endif + + + +#if !defined(HAVE_RES_INIT_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +int res_init(void); +#ifdef __cplusplus +} +#endif +#endif + + + +#if !defined(HAVE_STRLCAT_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +unsigned long strlcat(char*, const char*, unsigned long); +#ifdef __cplusplus +} +#endif +#endif + + + +#if !defined(HAVE_STRLCPY_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +unsigned long strlcpy(char*, const char*, unsigned long); +#ifdef __cplusplus +} +#endif +#endif + + + +/* + * On HP-UX, the declaration of vsnprintf() is needed every time ! + */ + +#if !defined(HAVE_VSNPRINTF) || defined(hpux) +#if __STDC__ +#include +#include +#else +#include +#endif +#ifdef __cplusplus +extern "C" +#endif +int vsnprintf(char *str, size_t n, char const *fmt, va_list ap); +#ifdef __cplusplus +extern "C" +#endif +int snprintf(char *str, size_t n, char const *fmt, ...); +#endif + + +/* define to 1 if -fvisibility is supported */ +#undef __KDE_HAVE_GCC_VISIBILITY + + +#if defined(__SVR4) && !defined(__svr4__) +#define __svr4__ 1 +#endif + + +/* type to use in place of socklen_t if not defined */ +#undef kde_socklen_t + +/* type to use in place of socklen_t if not defined (deprecated, use + kde_socklen_t) */ +#undef ksize_t diff --git a/configure.files b/configure.files new file mode 100644 index 0000000..486cc07 --- /dev/null +++ b/configure.files @@ -0,0 +1,4 @@ +./admin/configure.in.min +configure.in.in +./src/configure.in.bot +configure.in.bot diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..2907d98 --- /dev/null +++ b/configure.in @@ -0,0 +1,290 @@ +dnl ======================================================= +dnl FILE: ./admin/configure.in.min +dnl ======================================================= + +dnl This file is part of the KDE libraries/packages +dnl Copyright (C) 2001 Stephan Kulow (coolo@kde.org) + +dnl This file is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Library General Public +dnl License as published by the Free Software Foundation; either +dnl version 2 of the License, or (at your option) any later version. + +dnl This library 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 GNU +dnl Library General Public License for more details. + +dnl You should have received a copy of the GNU Library General Public License +dnl along with this library; see the file COPYING.LIB. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +dnl Boston, MA 02110-1301, USA. + +# Original Author was Kalle@kde.org +# I lifted it in some mater. (Stephan Kulow) +# I used much code from Janos Farkas + +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(acinclude.m4) dnl a source file from your sub dir + +dnl This is so we can use kde-common +AC_CONFIG_AUX_DIR(admin) + +dnl This ksh/zsh feature conflicts with `cd blah ; pwd` +unset CDPATH + +dnl Checking host/target/build systems, for make, install etc. +AC_CANONICAL_SYSTEM +dnl Perform program name transformation +AC_ARG_PROGRAM + +dnl Automake doc recommends to do this only here. (Janos) +AM_INIT_AUTOMAKE(gwenview-1.4.2, "3.5.7") dnl searches for some needed programs + +AM_MAINTAINER_MODE + +KDE_SET_PREFIX + +dnl generate the config header +AM_CONFIG_HEADER(config.h) dnl at the distribution this done + +dnl Checks for programs. +AC_CHECK_COMPILERS +AC_ENABLE_SHARED(yes) +AC_ENABLE_STATIC(no) +KDE_PROG_LIBTOOL + +dnl for NLS support. Call them in this order! +dnl WITH_NLS is for the po files +AM_KDE_WITH_NLS + +KDE_USE_QT(3.2) +AC_PATH_KDE +dnl ======================================================= +dnl FILE: configure.in.in +dnl ======================================================= + +#MIN_CONFIG(3.2) + +KDE_ENABLE_HIDDEN_VISIBILITY + +KDE_CHECK_LIB(m, lround, [ + AC_DEFINE(HAVE_LROUND, 1, [Define if you have lround]) +]) + +# +# KIPI +# +AC_ARG_WITH(kipi, + AC_HELP_STRING([--without-kipi], [build Gwenview without KIPI, 'KDE Image Plugin Interface']), + [want_kipi=$withval], + [want_kipi=yes] +) + +if test "$want_kipi" = "yes"; then + AC_MSG_NOTICE(checking if KIPI is installed) + KDE_CHECK_HEADER(libkipi/interface.h, + have_kipi=yes, + have_kipi=no) + + if test "$have_kipi" = "yes"; then + AC_DEFINE(GV_HAVE_KIPI, 1, [If we have libkipi installed]) + GV_LIB_KIPI="-lkipi" + AC_SUBST(GV_LIB_KIPI) + else + AC_MSG_WARN([KIPI is not installed. Gwenview will be build without KIPI support.]) + fi +fi + +# +# Imlib/Mosfet scaling +# +AM_PROG_AS + +# MMX test duped from kdelibs/kdefx - it should be probably moved to admin/ +dnl ----------------------------------------------------- +dnl IA32 checks +dnl ----------------------------------------------------- + +gv_asm_defs= +case $host_cpu in + i*86 ) + AC_MSG_CHECKING(for assembler support for IA32 extensions) + + dnl MMX check + AC_TRY_COMPILE(, [ __asm__("pxor %mm0, %mm0") ], + [ + echo $ECHO_N "MMX yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_MMX, 1, [Define to 1 if the assembler supports MMX instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_MMX" + ], [ echo $ECHO_N "MMX no$ECHO_C" ]) + + dnl SSE check + AC_TRY_COMPILE(,[ __asm__("xorps %xmm0, %xmm0") ], + [ + echo $ECHO_N ", SSE yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_SSE, 1, [Define to 1 if the assembler supports SSE instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_SSE" + ], [ echo $ECHO_N ", SSE no$ECHO_C" ]) + + dnl SSE2 check + AC_TRY_COMPILE(, [ __asm__("xorpd %xmm0, %xmm0") ], + [ + echo $ECHO_N ", SSE2 yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_SSE2, 1, [Define to 1 if the assembler supports SSE2 instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_SSE2" + ], [ echo $ECHO_N ", SSE2 no$ECHO_C" ]) + + dnl 3DNOW check + AC_TRY_COMPILE(, [ __asm__("femms") ], + [ + echo $ECHO_N ", 3DNOW yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_3DNOW, 1, [Define to 1 if the assembler supports 3DNOW instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_3DNOW" + ], [ echo $ECHO_N ", 3DNOW no$ECHO_C" ]) + echo + ;; + powerpc ) + AC_MSG_CHECKING(for assembler support for AltiVec instructions) + dnl AltiVec check + AC_TRY_COMPILE(, [ __asm__("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0" : : "r"(-1) ) ], + [ + echo $ECHO_N " yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_PPC_ALTIVEC, 1, [Define to 1 if the assembler supports AltiVec instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_PPC_ALTIVEC" + ], [ echo $ECHO_N ", AltiVec no$ECHO_C" ]) + echo + ;; +esac + +GV_ASM_DEFS="$gv_asm_defs" +AC_SUBST(GV_ASM_DEFS) + +# +# libmng check (for gvmngformattype.*) +# +LIBMNG= +KDE_CHECK_HEADER(libmng.h, + [ + KDE_CHECK_LIB(mng, mng_initialize, + [ + AC_DEFINE_UNQUOTED(HAVE_LIBMNG, 1, [Define if you have libmng]) + LIBMNG="-lmng $LIBZ -lm" + ], [], $LIBZ -lm) + ]) +AC_SUBST(LIBMNG) +if test -z "$LIBMNG"; then + AC_WARN([Can't find libmng.h, Gwenview won't be compiled with MNG support]) +fi + + +# +# libxcursor +# +KDE_CHECK_HEADERS(X11/Xcursor/Xcursor.h, + [KDE_CHECK_LIB(Xcursor, XcursorXcFileLoadImages, [ + GV_LIB_XCURSOR=-lXcursor + AC_DEFINE_UNQUOTED(GV_HAVE_XCURSOR, 1, [Define to 1 if you have Xcursor]) + ], [ GV_LIB_XCURSOR= ], [ $X_PRE_LIBS -lX11 $X_EXTRA_LIBS ])], + [ GV_LIB_XCURSOR= ], [#include ]) +AC_SUBST(GV_LIB_XCURSOR) +if test -z "$GV_LIB_XCURSOR"; then + AC_WARN([Can't find Xcursor.h, Gwenview won't be compiled with X cursor support]) +fi + + +# +# libexiv2 +# +KDE_CHECK_HEADERS(exiv2/image.hpp, have_exiv2=yes, have_exiv2=no) + +if test "$have_exiv2" = "yes"; then + LIB_EXIV2="-lexiv2" + AC_SUBST(LIB_EXIV2) +else + AC_MSG_ERROR([You are missing libexiv2, which is required to compile Gwenview]) + DO_NOT_COMPILE="$DO_NOT_COMPILE gwenview" +fi +KDE_CREATE_SUBDIRSLIST +AM_CONDITIONAL(doc_SUBDIR_included, test "x$doc_SUBDIR_included" = xyes) +AM_CONDITIONAL(src_SUBDIR_included, test "x$src_SUBDIR_included" = xyes) +AC_CONFIG_FILES([ Makefile ]) +AC_CONFIG_FILES([ doc/Makefile ]) +AC_CONFIG_FILES([ src/Makefile ]) +AC_CONFIG_FILES([ src/app/Makefile ]) +AC_CONFIG_FILES([ src/desktopfiles/Makefile ]) +AC_CONFIG_FILES([ src/doc/Makefile ]) +AC_CONFIG_FILES([ src/gvcore/Makefile ]) +AC_CONFIG_FILES([ src/gvdirpart/Makefile ]) +AC_CONFIG_FILES([ src/gvimagepart/Makefile ]) +AC_CONFIG_FILES([ src/imageutils/Makefile ]) +AC_CONFIG_FILES([ src/pics/Makefile ]) +AC_CONFIG_FILES([ src/pics/action/Makefile ]) +AC_CONFIG_FILES([ src/pics/app/Makefile ]) +AC_CONFIG_FILES([ src/pics/cursor/Makefile ]) +AC_CONFIG_FILES([ src/pics/thumbnail/Makefile ]) +AC_CONFIG_FILES([ src/tools/Makefile ]) +AC_CONFIG_FILES([ src/tsthread/Makefile ]) +AC_CONFIG_FILES([ src/updates/Makefile ]) +AC_OUTPUT +if test "$want_kipi" = "yes" ; then + if test "$have_kipi" != "yes" ; then + echo "" + echo "KIPI is not installed. Gwenview will be build without KIPI support." + echo "" + fi +else + echo "" + echo "KIPI support has been disabled. Gwenview will be build without KIPI support." + echo "" +fi +dnl Put here things to be done at the very end - telling users +dnl about additional packages to install. Better yet is giving +dnl each project / subdr its own configure.in.bot. + +# Check if KDE_SET_PREFIX was called, and --prefix was passed to configure +if test -n "$kde_libs_prefix" -a -n "$given_prefix"; then + # And if so, warn when they don't match + if test "$kde_libs_prefix" != "$given_prefix"; then + # And if kde doesn't know about the prefix yet + echo ":"`kde-config --path exe`":" | grep ":$given_prefix/bin/:" 2>&1 >/dev/null + if test $? -ne 0; then + echo "" + echo "Warning: you chose to install this package in $given_prefix," + echo "but KDE was found in $kde_libs_prefix." + echo "For this to work, you will need to tell KDE about the new prefix, by ensuring" + echo "that KDEDIRS contains it, e.g. export KDEDIRS=$given_prefix:$kde_libs_prefix" + echo "Then restart KDE." + echo "" + fi + fi +fi + +if test x$GXX = "xyes" -a x$kde_have_gcc_visibility = "xyes" -a x$kde_cv_val_qt_gcc_visibility_patched = "xno"; then + echo "" + echo "Your GCC supports symbol visibility, but the patch for Qt supporting visibility" + echo "was not included. Therefore, GCC symbol visibility support remains disabled." + echo "" + echo "For better performance, consider including the Qt visibility supporting patch" + echo "located at:" + echo "" + echo "http://bugs.kde.org/show_bug.cgi?id=109386" + echo "" + echo "and recompile all of Qt and KDE. Note, this is entirely optional and" + echo "everything will continue to work just fine without it." + echo "" +fi + +if test "$all_tests" = "bad"; then + if test ! "$cache_file" = "/dev/null"; then + echo "" + echo "Please remove the file $cache_file after changing your setup" + echo "so that configure will find the changes next time." + echo "" + fi +else + echo "" + echo "Good - your configure finished. Start make now" + echo "" +fi diff --git a/configure.in.bot b/configure.in.bot new file mode 100644 index 0000000..3b7eaa7 --- /dev/null +++ b/configure.in.bot @@ -0,0 +1,4 @@ +dnl Put here things to be done at the very end - telling users +dnl about additional packages to install. Better yet is giving +dnl each project / subdr its own configure.in.bot. + diff --git a/configure.in.in b/configure.in.in new file mode 100644 index 0000000..f51154e --- /dev/null +++ b/configure.in.in @@ -0,0 +1,141 @@ +#MIN_CONFIG(3.2) + +KDE_ENABLE_HIDDEN_VISIBILITY + +KDE_CHECK_LIB(m, lround, [ + AC_DEFINE(HAVE_LROUND, 1, [Define if you have lround]) +]) + +# +# KIPI +# +AC_ARG_WITH(kipi, + AC_HELP_STRING([--without-kipi], [build Gwenview without KIPI, 'KDE Image Plugin Interface']), + [want_kipi=$withval], + [want_kipi=yes] +) + +if test "$want_kipi" = "yes"; then + AC_MSG_NOTICE(checking if KIPI is installed) + KDE_CHECK_HEADER(libkipi/interface.h, + have_kipi=yes, + have_kipi=no) + + if test "$have_kipi" = "yes"; then + AC_DEFINE(GV_HAVE_KIPI, 1, [If we have libkipi installed]) + GV_LIB_KIPI="-lkipi" + AC_SUBST(GV_LIB_KIPI) + else + AC_MSG_WARN([KIPI is not installed. Gwenview will be build without KIPI support.]) + fi +fi + +# +# Imlib/Mosfet scaling +# +AM_PROG_AS + +# MMX test duped from kdelibs/kdefx - it should be probably moved to admin/ +dnl ----------------------------------------------------- +dnl IA32 checks +dnl ----------------------------------------------------- + +gv_asm_defs= +case $host_cpu in + i*86 ) + AC_MSG_CHECKING(for assembler support for IA32 extensions) + + dnl MMX check + AC_TRY_COMPILE(, [ __asm__("pxor %mm0, %mm0") ], + [ + echo $ECHO_N "MMX yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_MMX, 1, [Define to 1 if the assembler supports MMX instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_MMX" + ], [ echo $ECHO_N "MMX no$ECHO_C" ]) + + dnl SSE check + AC_TRY_COMPILE(,[ __asm__("xorps %xmm0, %xmm0") ], + [ + echo $ECHO_N ", SSE yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_SSE, 1, [Define to 1 if the assembler supports SSE instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_SSE" + ], [ echo $ECHO_N ", SSE no$ECHO_C" ]) + + dnl SSE2 check + AC_TRY_COMPILE(, [ __asm__("xorpd %xmm0, %xmm0") ], + [ + echo $ECHO_N ", SSE2 yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_SSE2, 1, [Define to 1 if the assembler supports SSE2 instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_SSE2" + ], [ echo $ECHO_N ", SSE2 no$ECHO_C" ]) + + dnl 3DNOW check + AC_TRY_COMPILE(, [ __asm__("femms") ], + [ + echo $ECHO_N ", 3DNOW yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_3DNOW, 1, [Define to 1 if the assembler supports 3DNOW instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_3DNOW" + ], [ echo $ECHO_N ", 3DNOW no$ECHO_C" ]) + echo + ;; + powerpc ) + AC_MSG_CHECKING(for assembler support for AltiVec instructions) + dnl AltiVec check + AC_TRY_COMPILE(, [ __asm__("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0" : : "r"(-1) ) ], + [ + echo $ECHO_N " yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_PPC_ALTIVEC, 1, [Define to 1 if the assembler supports AltiVec instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_PPC_ALTIVEC" + ], [ echo $ECHO_N ", AltiVec no$ECHO_C" ]) + echo + ;; +esac + +GV_ASM_DEFS="$gv_asm_defs" +AC_SUBST(GV_ASM_DEFS) + +# +# libmng check (for gvmngformattype.*) +# +LIBMNG= +KDE_CHECK_HEADER(libmng.h, + [ + KDE_CHECK_LIB(mng, mng_initialize, + [ + AC_DEFINE_UNQUOTED(HAVE_LIBMNG, 1, [Define if you have libmng]) + LIBMNG="-lmng $LIBZ -lm" + ], [], $LIBZ -lm) + ]) +AC_SUBST(LIBMNG) +if test -z "$LIBMNG"; then + AC_WARN([Can't find libmng.h, Gwenview won't be compiled with MNG support]) +fi + + +# +# libxcursor +# +KDE_CHECK_HEADERS(X11/Xcursor/Xcursor.h, + [KDE_CHECK_LIB(Xcursor, XcursorXcFileLoadImages, [ + GV_LIB_XCURSOR=-lXcursor + AC_DEFINE_UNQUOTED(GV_HAVE_XCURSOR, 1, [Define to 1 if you have Xcursor]) + ], [ GV_LIB_XCURSOR= ], [ $X_PRE_LIBS -lX11 $X_EXTRA_LIBS ])], + [ GV_LIB_XCURSOR= ], [#include ]) +AC_SUBST(GV_LIB_XCURSOR) +if test -z "$GV_LIB_XCURSOR"; then + AC_WARN([Can't find Xcursor.h, Gwenview won't be compiled with X cursor support]) +fi + + +# +# libexiv2 +# +KDE_CHECK_HEADERS(exiv2/image.hpp, have_exiv2=yes, have_exiv2=no) + +if test "$have_exiv2" = "yes"; then + LIB_EXIV2="-lexiv2" + AC_SUBST(LIB_EXIV2) +else + AC_MSG_ERROR([You are missing libexiv2, which is required to compile Gwenview]) + DO_NOT_COMPILE="$DO_NOT_COMPILE gwenview" +fi diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..26d239d --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,2 @@ +KDE_LANG = en +KDE_DOCS = gwenview diff --git a/doc/browse_mode.png b/doc/browse_mode.png new file mode 100644 index 0000000..48f463b Binary files /dev/null and b/doc/browse_mode.png differ diff --git a/doc/dock_grip.png b/doc/dock_grip.png new file mode 100644 index 0000000..04c090d Binary files /dev/null and b/doc/dock_grip.png differ diff --git a/doc/docked_windows.docbook b/doc/docked_windows.docbook new file mode 100644 index 0000000..b5a14e3 --- /dev/null +++ b/doc/docked_windows.docbook @@ -0,0 +1,70 @@ +Docked windows +The &kappname; interface is composed of a number of smaller docked windows. +Manipulating these windows can be difficult at first. To focus a particular +window in the &kappname; interface, simply click within it. + +Each docked window has a small grip bar along the top. It contains a dock/undock button +resembling an arrow at its right end and a close button resembling the +letter X. It looks like this: + + + Grip bar of a docked window + + + + + + Grip bar of a docked window + + + + + + + Clicking the close button on a docked window will remove it from the interface. +To bring it back, select its name in the Window +menu. + + + To resize docked windows, drag the border between the + windows. + + + + To re-arrange the docked windows, drag a window by its grip bar + over to the desired position. While dragging, a small box + outline will appear to indicate the position the window + will take when you end the drag. + + If you wish to stack two windows and use tabs to choose between them, + drag the window to the very center of the other window with which you wish + to stack. + + + + To undock a window, either click the dock/undock button in its top right corner, or + double-click on the window's grip bar. + Double-clicking again or clicking on the dock/undock button, should return the window to its original + position. + You can also dock an undocked window by dragging its grip bar back to a +point within the general interface, just as if you were rearranging an already +docked window. + + + + The file view window cannot be undocked or moved, but by moving other windows + around, it can itself be shifted about. + + + + While dragging a window, press the Escape key to cancel the operation. To reset + the docked windows to the default &kappname; layout, use + + Window + Reset + . + + + + + diff --git a/doc/external_tools.docbook b/doc/external_tools.docbook new file mode 100644 index 0000000..5e91890 --- /dev/null +++ b/doc/external_tools.docbook @@ -0,0 +1,69 @@ + +External tools + +You can easily extend &kappname; by defining external tools. These tools + are accessible from the contextual popup menu which appears when + right-clicking on a thumbnail or in the image view. Look in the + External Tools entry. + +&kappname; comes with a few predefined external tools, but it's very + easy to add more through the Configure External Tools dialog. You can open + it from SettingsConfigure + External Tools.... + + +Here is how it looks: + + + External tools dialog + + + + + + + + +In this example, I defined an external tool which will call Exiftran to + regenerate the EXIF tags for JPEG images. Here is a more detailed description + of its definition: + + + + The Name: field contains the description of your + tool, has it will appear in the menu. + + + + The Command: field contains the command which + will be run when this tool is invoked. + Click on the little question mark on the right of the field to get a list + of the keywords you can use in this field. These keywords will get + expanded to the image files. + + + + + The button on the right lets you associate an icon with your tool. + + + + + The File Associations group indicates what type of + files this tool can work with. Your tool will only appear in the + External Tools menu if the + selected files are of the correct type. In my example, this tool is only + valid with JPEG images, so I choose Custom:, then + image/jpeg and image/pjpeg. + + + + + + You can find other external tool examples from + &kappname; web site. + + + + + diff --git a/doc/external_tools_dialog.png b/doc/external_tools_dialog.png new file mode 100644 index 0000000..72e6723 Binary files /dev/null and b/doc/external_tools_dialog.png differ diff --git a/doc/index.docbook b/doc/index.docbook new file mode 100644 index 0000000..637b8dc --- /dev/null +++ b/doc/index.docbook @@ -0,0 +1,64 @@ + + + + + + + + + + + +]> + + +Gwenview User Manual + + + + +Aurélien +Gâteau +
aurelien.gateau@free.fr
+
+ +ChristopherMartin +
chrsmrtn@debian.org
+
+
+ + +2005 +Aurélien Gâteau + + + +2005-08-21 +1.2.92 + +&kappname; is an image viewer for KDE. + + +KDE +image +viewer +artist +photo +picture + +
+&introduction; +&interface; + +&external_tools; + + +Tips +&mouse; +&keybindings; +&docked_windows; + + +
diff --git a/doc/interface.docbook b/doc/interface.docbook new file mode 100644 index 0000000..1d17e0b --- /dev/null +++ b/doc/interface.docbook @@ -0,0 +1,50 @@ + +The interface + +Browse and View modes + +By default, &kappname; opens in Browse mode. + +In this mode you can easily navigate through your files and folders. As + you can see on the screenshot, the preview window shows the current image as + well as any embedded image comment. + + + Browse Mode Screenshot + + + + + + + + +From the Browse mode, + unchecking + + + &Ctrl;Return + + View + Browse + + will put you in View mode, where the image takes all the + space of the window. + + + View Mode Screenshot + + + + + + + +You can start directly in View mode by starting &kappname; with an image + as an argument. + + + + + + diff --git a/doc/introduction.docbook b/doc/introduction.docbook new file mode 100644 index 0000000..9ea1995 --- /dev/null +++ b/doc/introduction.docbook @@ -0,0 +1,27 @@ + +Introduction + + +What is &kappname; + + +&kappname; is a fast and easy to use image viewer for KDE. + + + +It features a folder tree window and a file list window to provide easy +navigation of your file hierarchy. &kappname; uses docked windows, so you can +alter its layout any way you wish. You can also browse your images in +full-screen mode, or embedded within &konqueror; using the Image View and Kpart. + +Image loading is handled by the Qt library, so &kappname; supports all +image formats your Qt installation supports. &kappname; correctly displays images +with an alpha channel as well as animations. + +&kappname; supports the displaying and editing of EXIF comments in JPEG +images. Lossless JPEG transforms such as rotations and mirroring are also supported. + + + + + diff --git a/doc/keybindings.docbook b/doc/keybindings.docbook new file mode 100644 index 0000000..f01b28c --- /dev/null +++ b/doc/keybindings.docbook @@ -0,0 +1,21 @@ + +Key bindings + +&kappname; comes with a range of keyboard shortcuts, all of which can be viewed and remapped by + selecting SettingsConfigure + Shortcuts.... Note that in the Files and Folders windows, +all the normal KDE shortcuts are functional, unless otherwise remapped. + +A few of the most useful default bindings are: + + + Space: Displays the next image in the directory. + Backspace: Displays the previous image in the directory. + &Ctrl;Return: Toggles between Browse and View modes. + &Ctrl; + &Shift;F: Activates Full Screen mode. + Escape: Exits from Full Screen mode. + + + diff --git a/doc/mouse.docbook b/doc/mouse.docbook new file mode 100644 index 0000000..b1f6d62 --- /dev/null +++ b/doc/mouse.docbook @@ -0,0 +1,41 @@ +Using the mouse + +Panning with the mouse + + Holding down the left mouse button on an image allows you to + scroll the image. + The mouse wheel will scroll the image up and + down. + + + + +Zooming with the mouse + + Clicking the middle mouse button will toggle the auto zoom + on/off. + Hold down the Control key, then either use the mouse wheel to + zoom in and out or left click to zoom in and right click to zoom + out. + + The mouse wheel, used while holding down the Alt key, will + scroll the image horizontally. + + + + +Browsing with the mouse + + Double-clicking on an image toggles Browse + mode. + By default, the mouse wheel will scroll the image up and down. But, + this can be configured to browse the images in the current directory + instead. + Hold down the left mouse button over an image, then click the right + button to go to the next image. + Hold down the right button, then click the + left button to load the previous image. + + + + diff --git a/doc/view_mode.png b/doc/view_mode.png new file mode 100644 index 0000000..bff633d Binary files /dev/null and b/doc/view_mode.png differ diff --git a/src/CREDITS b/src/CREDITS new file mode 100644 index 0000000..4dc9531 --- /dev/null +++ b/src/CREDITS @@ -0,0 +1,88 @@ +CURRENT PACKAGERS +----------------- + +ASP Linux: + Andrew "nording" Chernyak + +Debian: + Christopher Martin + +Fedora Core: + Domenico Cotroneo + +Mandriva: + Angelo Naselli + +Red Hat: + Bobby Rockers + +SuSE: + Sarah "cokie" Jaromij + +Slackware: + Mark Tucker + + +PAST PACKAGERS +-------------- + +These fine people contributed binary packages: + +Red Hat: + Ian Koenig + +SuSE 7.2: + Dario Abatianni + +SuSE 9.0: + Marco Puszina + +Debian: + Michael Spanier + +Slackware: + Luca Cavalli + + +TRANSLATORS +----------- + +Back in the days when Gwenview was not in KDE Extra Gear, the following nice +people contributed translations. + +Dutch: + Rindert Vonk + +German: + Robert Gogolok + +Hungarian: + Arpad Biro + +Italian: + Marco De Simone + +Japanese: + Ryota Simamoto + +Korean: + Park Yu-Chan + +Norwegian: + Rune Nordvik + +Polish: + Szymon Janc + +Spanish: + Daniel R. Ome + +Swedish: + Karolina Lindqvist + + +Now translations are done by the KDE translation teams, so I don't really know +how are the translators. I guess some of the people I quoted here are still +working on translating Gwenview. + +Thanks to all of you. diff --git a/src/DESIGN b/src/DESIGN new file mode 100644 index 0000000..fcb0e3f --- /dev/null +++ b/src/DESIGN @@ -0,0 +1,142 @@ +# Folders + +Here is a description of each folder: + +* app/ + Code specific to the standalone application (== not the KParts) + +* desktopfiles/ + Desktop files, to start the standalone application, from the menu and from + within Konqueror. + +* doc/ + Man page. This is not the HTML doc. The HTML doc is in + extragear/graphics/doc/gwenview. + +* gvcore/ + Code shared between the application and the KParts. + +* gvdirpart/ + The Gwenview KPart used to browse folders. + +* gvimagepart/ + The Gwenview KPart to display images. + +* imageutils/ + Various image code, like rotation (lossless for JPEG, classic for others), + scaling... + +* pics/ + Icons. + +* spec/ + .spec files to build RPM (probably outdated) + +* tools/ + Desktop files describing external tools. + +* tsthread/ + A thread library written by Lubos Lunak. + +* updates/ + Update scripts to migrate configuration files within versions. + + +# Code + +In this part we describe the main classes, not getting too deeply into details +so that this document doesn't get obsoleted too fast :-) + + +## gvcore +### Document classes +document.h +document*impl.h + +This is the heart of Gwenview. The Document class represents a media file. It +uses the "State" design pattern to adapt its behavior depending on its state. +The various states are implemented in the Document*Impl classes. +It knows how to load, save, edit a comment, rotate and mirror a document. + + +### Image loader and cache +imageloader.h +cache.h + +Image loading is done by the ImageLoader classes, which work together with the +cache to avoid loading an image multiple times. +A loader may be shared, for example if an image is selected and a thumbnail of +it is being generated, the same loader will be used by both. + + +### File views +fileviewcontroller.h +filedetailview*.h +filethumbnailview*.h +fileviewbase.h + +The main class is FileViewController, which contains the KDirLister responsible +for listing folder content. It also contains a QWidgetStack which contains +both the FileDetailView and the FileThumbnailView. +FileViewBase is an abstract class, which inherits from KFileView and adds the +concept of a "shown item": the item currently viewed in the image view. + + +### Image view +imageview.h +imageviewtools.h + +The ImageView class inherits from QScrollView to show the current image. It +implements zooming and panning. +The ImageViewTools implements the different behaviors: for example when you +use the mouse wheel you will scroll (or browse): This is implemented by the +ImageView::ScrollTool class. If you press Ctrl and use the mouse wheel, you +will zoom in the image: This is implemented by the ImageView::ZoomTool. + + +### ImageViewController + +ImageViewController contains a stack which contains an ImageView and a KPart. +The ImageView class is used to show raster images. For SVG images and movies, +the ImageViewController loads the corresponding KPart. + + +### File operations +fileoperation.h +fileopobject.h + +These classes implements file operations: from the user interface to the actual +operation. + + +## app + +### Main window +mainwindow.h + +The MainWindow class is responsible for gluing together all components of the +application. It is made of a QWidgetStack which contains two pages: one for +the docked windows (==Browse mode) and another for the ImageViewController +(==View and Fullscreen modes). +There is only one instance of ImageViewController. It is 'reparent'ed when the +QWidgetStack switch between modes. + + +### Folder view +dirviewcontroller.h +vtabwidget.h +bookmarkviewcontroller.h +treeview.h + +These classes implement the folder view. The main class is DirViewController. +It contains a VTabWidget, which contains an instance of the +BoookmarkViewController and TreeView classes. + + +## gvdirpart + +This KPart is made of a splitter, a FileThumbnailView and an ImageView. + +## gvimagepart + +This KPart is simply an ImageView. diff --git a/src/HACKING b/src/HACKING new file mode 100644 index 0000000..599dd3b --- /dev/null +++ b/src/HACKING @@ -0,0 +1,95 @@ +This file describes the coding conventions used in Gwenview. + + +Naming +------ + +Classes should be named like this: MyClass. The class MyClass should be defined +in the myclass.h file and implemented in myclass.cpp. + +Variables and functions should be named like this: myVariable. Static and +member variables are identified by a prefix (s or m), without underscore. + +int sStaticVariable. + +class MyClass { + int mMemberVariable; + + void doSomething() { + int localVariable; + } +}; + + +Enum items and consts are spelled like this: + +const int MY_CONST_VALUE=120; +enum AnEnum { ITEM1, ITEM2, ITEM3 }; + + +Namespace +--------- + +All code should be enclosed in the "Gwenview" namespace. Make sure the closing +curly bracket of the namespace looks like this : + +} // namespace + +This avoids wondering why the curly bracket is here. + + +Code layout +----------- + +Use tabs, not spaces. + +The opening brace follows the function/class/for/while. Insert a space after +commas and after for/while keywords. + +void myFunction() { + int v1; + int v2=12; + for (v1=0; v1<10; ++v1) { + doSomething(v1, v2); + } +} + +class MyClass { +}; + + +If the if content is only one line long, you can place it on the same line and +omit the curly braces, but DO NOT omit them if you place the content after the +if. + +// Ok +if (!data) { + return; +} + +// Ok too +if (!data) return; + +// Bad +if (!data) + return; + + +Include files +------------- + +Group include files in the Qt, KDE or local groups and sort them +alphabetically. When writing the implementation file of a class which is a +Q_OBJECT, make sure you include the .moc file, not the .h. + +// Qt +#include +#include + +// KDE +#include +#include + +// Local +#include "aclass.h" +#include "myclass.moc" diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..81a3b05 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,8 @@ +SUBDIRS = tsthread imageutils gvcore pics desktopfiles doc tools updates gvimagepart gvdirpart app + +EXTRA_DIST = AUTHORS ChangeLog COPYING INSTALL NEWS README TODO CREDITS DESIGN + +messages: rc.cpp + $(EXTRACTRC) `find . -name "*.ui"` >> rc.cpp + $(EXTRACTRC) `find . -name "*.rc"` >> rc.cpp + $(XGETTEXT) `find . -name "*.cpp"` `find . -name "*.h"` -o $(podir)/gwenview.pot diff --git a/src/app/.vimrc b/src/app/.vimrc new file mode 100644 index 0000000..a37475c --- /dev/null +++ b/src/app/.vimrc @@ -0,0 +1,4 @@ +set tabstop=4 +set shiftwidth=4 +set noexpandtab +set makeprg=unsermake diff --git a/src/app/Makefile.am b/src/app/Makefile.am new file mode 100644 index 0000000..037933a --- /dev/null +++ b/src/app/Makefile.am @@ -0,0 +1,56 @@ +bin_PROGRAMS= +lib_LTLIBRARIES= + +kdeinit_LTLIBRARIES = gwenview.la + +# -D_LARGEFILE64_SOURCE is necessary on Debian Woody +AM_CPPFLAGS = -D_LARGEFILE64_SOURCE + +noinst_LTLIBRARIES = libgwenshared.la + +libgwenshared_la_SOURCES = vtabwidget.cpp + +gwenview_COMPILE_FIRST = ../gvcore/miscconfig.h ../gvcore/slideshowconfig.h ../gvcore/fileoperationconfig.h ../gvcore/fullscreenconfig.h ../gvcore/imageviewconfig.h ../gvcore/fileviewconfig.h + +gwenview_la_SOURCES = \ + bookmarkowner.cpp \ + bookmarkviewcontroller.cpp \ + bookmarkdialogbase.ui \ + bookmarkdialog.cpp \ + configfileoperationspage.ui \ + configfullscreenpage.ui \ + configimagelistpage.ui \ + configimageviewpage.ui \ + configmiscpage.ui \ + configslideshowpage.ui \ + kipiinterface.cpp \ + mainwindow.cpp \ + metaedit.cpp \ + treeview.cpp \ + dirviewcontroller.cpp \ + configdialog.cpp \ + history.cpp \ + main.cpp + +gwenview_la_LIBADD = libgwenshared.la ../gvcore/libgwenviewcore.la $(GV_LIB_KIPI) $(LIB_KUTILS) + +# the library search path. +gwenview_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + + +# set the include path for X, qt and KDE +INCLUDES = -I$(srcdir)/.. $(all_includes) + +METASOURCES = AUTO + +rcdir = $(kde_datadir)/gwenview +rc_DATA = gwenviewui.rc + + +check_PROGRAMS = testvtabwidget +testvtabwidget_SOURCES = testvtabwidget.cpp +testvtabwidget_LDADD = \ + libgwenshared.la \ + $(LIB_KUTILS) $(LIB_KFILE) $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_KDEPRINT) $(LIB_QT) \ + $(LIBJPEG) +testvtabwidget_LDFLAGS = $(all_libraries) diff --git a/src/app/bookmarkdialog.cpp b/src/app/bookmarkdialog.cpp new file mode 100644 index 0000000..0572fc2 --- /dev/null +++ b/src/app/bookmarkdialog.cpp @@ -0,0 +1,115 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "bookmarkdialog.moc" +// Qt +#include + +// KDE +#include +#include +#include +#include +#include + +// Local +#include "bookmarkdialogbase.h" +namespace Gwenview { + +class BookmarkDialogPrivate { +public: + BookmarkDialogBase* mContent; + BookmarkDialog::Mode mMode; +}; + +BookmarkDialog::BookmarkDialog(QWidget* parent, BookmarkDialog::Mode mode) +: KDialogBase(parent,"folderconfig",true,QString::null,Ok|Cancel) +{ + d=new BookmarkDialogPrivate; + d->mContent=new BookmarkDialogBase(this); + d->mMode=mode; + + setMainWidget(d->mContent); + setCaption(d->mContent->caption()); + d->mContent->mUrl->setMode(KFile::Directory); + d->mContent->mIcon->setIcon("folder"); + + connect(d->mContent->mTitle,SIGNAL(textChanged(const QString&)), + this, SLOT(updateOk())); + connect(d->mContent->mIcon,SIGNAL(iconChanged(QString)), + this, SLOT(updateOk())); + + if (mode==BOOKMARK_GROUP) { + d->mContent->mUrlLabel->hide(); + d->mContent->mUrl->hide(); + } else { + connect(d->mContent->mUrl,SIGNAL(textChanged(const QString&)), + this, SLOT(updateOk())); + } + + switch (mode) { + case BOOKMARK_GROUP: + setCaption( i18n("Add/Edit Bookmark Folder") ); + break; + case BOOKMARK: + setCaption( i18n("Add/Edit Bookmark") ); + break; + } + + updateOk(); +} + +BookmarkDialog::~BookmarkDialog() { + delete d; +} + +void BookmarkDialog::updateOk() { + bool enabled= + !d->mContent->mTitle->text().isEmpty() + && (d->mMode==BOOKMARK_GROUP || !d->mContent->mUrl->url().isEmpty()); + + enableButton(Ok, enabled); +} + +void BookmarkDialog::setIcon(const QString& icon) { + d->mContent->mIcon->setIcon(icon); +} + +QString BookmarkDialog::icon() const { + return d->mContent->mIcon->icon(); +} + +void BookmarkDialog::setTitle(const QString& title) { + d->mContent->mTitle->setText(title); +} + +QString BookmarkDialog::title() const { + return d->mContent->mTitle->text(); +} + +void BookmarkDialog::setURL(const QString& url) { + d->mContent->mUrl->setURL(url); +} + +QString BookmarkDialog::url() const { + return d->mContent->mUrl->url(); +} + +} // namespace diff --git a/src/app/bookmarkdialog.h b/src/app/bookmarkdialog.h new file mode 100644 index 0000000..46f4aaf --- /dev/null +++ b/src/app/bookmarkdialog.h @@ -0,0 +1,54 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef BOOKMARKDIALOG_H +#define BOOKMARKDIALOG_H + +// KDE includes +#include +namespace Gwenview { + +class BookmarkDialogPrivate; + +class BookmarkDialog : public KDialogBase { +Q_OBJECT +public: + enum Mode { BOOKMARK_GROUP, BOOKMARK }; + BookmarkDialog(QWidget* parent, Mode mode); + ~BookmarkDialog(); + + + void setIcon(const QString&); + QString icon() const; + void setTitle(const QString&); + QString title() const; + void setURL(const QString&); + QString url() const; + +protected slots: + void updateOk(); + +private: + BookmarkDialogPrivate* d; +}; + +} // namespace +#endif + diff --git a/src/app/bookmarkdialogbase.ui b/src/app/bookmarkdialogbase.ui new file mode 100644 index 0000000..4768e4f --- /dev/null +++ b/src/app/bookmarkdialogbase.ui @@ -0,0 +1,109 @@ + +BookmarkDialogBase + + + BookmarkDialogBase + + + + 0 + 0 + 500 + 90 + + + + + 1 + 5 + 0 + 0 + + + + + 400 + 0 + + + + Add New Branch + + + + unnamed + + + 0 + + + + mUrlLabel + + + URL: + + + + + mTitle + + + + + mUrl + + + + + textLabel2 + + + Title: + + + + + textLabel2_2 + + + Icon: + + + + + mIcon + + + + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 383 + 16 + + + + + + + + + + klineedit.h + kurlrequester.h + klineedit.h + kpushbutton.h + + diff --git a/src/app/bookmarkowner.cpp b/src/app/bookmarkowner.cpp new file mode 100644 index 0000000..ac484e7 --- /dev/null +++ b/src/app/bookmarkowner.cpp @@ -0,0 +1,53 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// KDE +#include + +// Local +#include "bookmarkowner.moc" +namespace Gwenview { + + +BookmarkOwner::BookmarkOwner(QWidget* parent) +: QObject(parent) +{} + + +void BookmarkOwner::openBookmarkURL(const QString& strURL) +{ + KURL url(strURL); + emit openURL(url); +} + + +QString BookmarkOwner::currentURL() const +{ + return mURL.prettyURL(); +} + + +void BookmarkOwner::setURL(const KURL& url) +{ + mURL=url; +} + +} // namespace diff --git a/src/app/bookmarkowner.h b/src/app/bookmarkowner.h new file mode 100644 index 0000000..85dab1b --- /dev/null +++ b/src/app/bookmarkowner.h @@ -0,0 +1,53 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef BOOKMARKOWNER_H +#define BOOKMARKOWNER_H + + +// KDE includes +#include +#include +namespace Gwenview { + + +class BookmarkOwner : public QObject, public KBookmarkOwner { +Q_OBJECT +public: + BookmarkOwner(QWidget* parent); + + // KBookmarkOwner interface + void openBookmarkURL(const QString&); + QString currentURL() const; + +public slots: + void setURL(const KURL&); + +signals: + void openURL(const KURL&); + +private: + KURL mURL; +}; + + +} // namespace +#endif + diff --git a/src/app/bookmarkviewcontroller.cpp b/src/app/bookmarkviewcontroller.cpp new file mode 100644 index 0000000..7fb4daa --- /dev/null +++ b/src/app/bookmarkviewcontroller.cpp @@ -0,0 +1,415 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2005 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "bookmarkviewcontroller.moc" + +#include + +// Qt +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "bookmarkdialog.h" +#include "../gvcore/fileoperation.h" + +namespace Gwenview { + +// URLDropListView +URLDropListView::URLDropListView(QWidget* parent) +: KListView(parent) { + setAcceptDrops(true); +} + + +void URLDropListView::contentsDragMoveEvent(QDragMoveEvent* event) { + if (KURLDrag::canDecode(event)) { + event->accept(); + } else { + event->ignore(); + } +} + + + + +struct BookmarkItem : public KListViewItem { + template + BookmarkItem(ItemParent* parent, const KBookmark& bookmark) + : KListViewItem(parent) + , mBookmark(bookmark) + { + refresh(); + } + + void refresh() { + setText(0, mBookmark.text() ); + setPixmap(0, SmallIcon(mBookmark.icon()) ); + } + + KBookmark mBookmark; +}; + + +class BookmarkToolTip : public QToolTip { +public: + BookmarkToolTip(KListView* lv) + : QToolTip(lv->viewport()) + , mListView(lv) {} + + void maybeTip(const QPoint& pos) { + BookmarkItem *item = static_cast( mListView->itemAt(pos) ); + if ( !item) return; + if (item->mBookmark.isGroup()) return; + + QRect rect=mListView->itemRect(item); + tip(rect, item->mBookmark.url().prettyURL()); + }; + + KListView* mListView; +}; + + +struct BookmarkViewController::Private { + QVBox* mBox; + KListView* mListView; + KBookmarkManager* mManager; + KURL mCurrentURL; + std::auto_ptr mToolTip; + KActionCollection* mActionCollection; + KURL mDroppedURL; + + template + void addGroup(ItemParent* itemParent, const KBookmarkGroup& group) { + KBookmark bookmark=group.first(); + BookmarkItem* previousItem=0; + BookmarkItem* item=0; + for (;!bookmark.isNull(); bookmark=group.next(bookmark) ) { + if (bookmark.isSeparator()) continue; + + // Create the item and make sure it's placed at the end + previousItem=item; + item=new BookmarkItem(itemParent, bookmark); + if (previousItem) { + item->moveItem(previousItem); + } + + if (bookmark.isGroup()) { + addGroup(item, static_cast(bookmark) ); + } + } + } + + KBookmarkGroup findBestParentGroup() { + KBookmarkGroup parentGroup; + BookmarkItem* item=static_cast( mListView->currentItem() ); + if (item) { + if (item->mBookmark.isGroup()) { + parentGroup=item->mBookmark.toGroup(); + } else { + parentGroup=item->mBookmark.parentGroup(); + } + } else { + parentGroup=mManager->root(); + } + + return parentGroup; + } + + void bookmarkURL(const KURL& url) { + BookmarkDialog dialog(mListView, BookmarkDialog::BOOKMARK); + dialog.setTitle(url.fileName()); + dialog.setURL(url.prettyURL()); + dialog.setIcon(KMimeType::iconForURL(url)); + if (dialog.exec()==QDialog::Rejected) return; + + KBookmarkGroup parentGroup=findBestParentGroup(); + parentGroup.addBookmark(mManager, dialog.title(), dialog.url(), dialog.icon()); + mManager->emitChanged(parentGroup); + } +}; + + +void URLDropListView::contentsDropEvent(QDropEvent* event) { + KURL::List urls; + if (!KURLDrag::decode(event, urls)) return; + emit urlDropped(event, urls); +} + + +BookmarkViewController::BookmarkViewController(QWidget* parent) +: QObject(parent) +{ + d=new Private; + d->mManager=0; + + d->mBox=new QVBox(parent); + + // Init listview + d->mListView=new URLDropListView(d->mBox); + d->mToolTip.reset(new BookmarkToolTip(d->mListView) ); + d->mActionCollection=new KActionCollection(d->mListView); + + d->mListView->header()->hide(); + d->mListView->setRootIsDecorated(true); + d->mListView->addColumn(QString::null); + d->mListView->setSorting(-1); + d->mListView->setShowToolTips(false); + d->mListView->setFullWidth(true); + + connect(d->mListView, SIGNAL(clicked(QListViewItem*)), + this, SLOT(slotOpenBookmark(QListViewItem*)) ); + connect(d->mListView, SIGNAL(returnPressed(QListViewItem*)), + this, SLOT(slotOpenBookmark(QListViewItem*)) ); + connect(d->mListView, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)), + this, SLOT(slotContextMenu(QListViewItem*)) ); + connect(d->mListView, SIGNAL(urlDropped(QDropEvent*, const KURL::List&)), + this, SLOT(slotURLDropped(QDropEvent*, const KURL::List&)) ); + + // Init toolbar + KToolBar* toolbar=new KToolBar(d->mBox, "", true); + KAction* action; + toolbar->setIconText(KToolBar::IconTextRight); + action=new KAction(i18n("Add a bookmark (keep it short)", "Add"), "bookmark_add", 0, + this, SLOT(bookmarkCurrentURL()), d->mActionCollection); + action->plug(toolbar); + action=new KAction(i18n("Remove a bookmark (keep it short)", "Remove"), "editdelete", 0, + this, SLOT(deleteCurrentBookmark()), d->mActionCollection); + action->plug(toolbar); +} + + +BookmarkViewController::~BookmarkViewController() { + delete d; +} + + +void BookmarkViewController::init(KBookmarkManager* manager) { + // This method should not be called twice + Q_ASSERT(!d->mManager); + + d->mManager=manager; + // For now, we ignore the caller parameter and just refresh the full list on update + connect(d->mManager, SIGNAL(changed(const QString&, const QString&)), + this, SLOT(fill()) ); + fill(); +} + + +void BookmarkViewController::setURL(const KURL& url) { + d->mCurrentURL=url; +} + + +QWidget* BookmarkViewController::widget() const { + return d->mBox; +} + + +void BookmarkViewController::fill() { + d->mListView->clear(); + KBookmarkGroup root=d->mManager->root(); + d->addGroup(d->mListView, root); +} + + +void BookmarkViewController::slotURLDropped(QDropEvent* event, const KURL::List& urls) { + // Get a pointer to the drop item + QPoint point(0,event->pos().y()); + KListView* lst=d->mListView; + BookmarkItem* item=static_cast( lst->itemAt(lst->contentsToViewport(point)) ); + + QPopupMenu menu(lst); + int addBookmarkID=menu.insertItem( SmallIcon("bookmark_add"), i18n("&Add Bookmark"), + this, SLOT(slotBookmarkDroppedURL()) ); + if (urls.count()==1) { + d->mDroppedURL=*urls.begin(); + } else { + menu.setItemEnabled(addBookmarkID, false); + } + + if (item) { + menu.insertSeparator(); + KURL dest=item->mBookmark.url(); + FileOperation::fillDropURLMenu(&menu, urls, dest); + } + + menu.insertSeparator(); + menu.insertItem( SmallIcon("cancel"), i18n("Cancel") ); + menu.exec(QCursor::pos()); +} + + +void BookmarkViewController::slotBookmarkDroppedURL() { + d->bookmarkURL(d->mDroppedURL); +} + + +void BookmarkViewController::slotOpenBookmark(QListViewItem* item_) { + if (!item_) return; + BookmarkItem* item=static_cast(item_); + const KURL& url=item->mBookmark.url(); + if (!url.isValid()) return; + emit openURL(url); +} + + +void BookmarkViewController::slotContextMenu(QListViewItem* item_) { + BookmarkItem* item=static_cast(item_); + QPopupMenu menu(d->mListView); + menu.insertItem(SmallIcon("bookmark_add"), i18n("Add Bookmark..."), + this, SLOT(bookmarkCurrentURL())); + menu.insertItem(SmallIcon("bookmark_folder"), i18n("Add Bookmark Folder..."), + this, SLOT(addBookmarkGroup())); + + if (item) { + menu.insertSeparator(); + menu.insertItem(SmallIcon("edit"), i18n("Edit..."), + this, SLOT(editCurrentBookmark())); + menu.insertItem(SmallIcon("editdelete"), i18n("Delete"), + this, SLOT(deleteCurrentBookmark())); + } + menu.exec(QCursor::pos()); +} + + +void BookmarkViewController::bookmarkCurrentURL() { + d->bookmarkURL(d->mCurrentURL); +} + + +void BookmarkViewController::addBookmarkGroup() { + BookmarkDialog dialog(d->mListView, BookmarkDialog::BOOKMARK_GROUP); + if (dialog.exec()==QDialog::Rejected) return; + + KBookmarkGroup parentGroup=d->findBestParentGroup(); + KBookmarkGroup newGroup=parentGroup.createNewFolder(d->mManager, dialog.title()); + newGroup.internalElement().setAttribute("icon", dialog.icon()); + d->mManager->emitChanged(parentGroup); + QListViewItem* item=d->mListView->currentItem(); + if (item) { + item->setOpen(true); + } +} + + +void BookmarkViewController::editCurrentBookmark() { + BookmarkItem* item=static_cast( d->mListView->currentItem() ); + Q_ASSERT(item); + if (!item) return; + KBookmark bookmark=item->mBookmark; + bool isGroup=bookmark.isGroup(); + + BookmarkDialog dialog(d->mListView, + isGroup ? BookmarkDialog::BOOKMARK_GROUP : BookmarkDialog::BOOKMARK); + + dialog.setIcon(bookmark.icon()); + dialog.setTitle(bookmark.text()); + if (!isGroup) { + dialog.setURL(bookmark.url().prettyURL()); + } + if (dialog.exec()==QDialog::Rejected) return; + + QDomElement element=bookmark.internalElement(); + element.setAttribute("icon", dialog.icon()); + if (!isGroup) { + element.setAttribute("href", dialog.url()); + } + + // Find title element (or create it if it does not exist) + QDomElement titleElement; + QDomNode tmp=element.namedItem("title"); + if (tmp.isNull()) { + titleElement=element.ownerDocument().createElement("title"); + element.appendChild(titleElement); + } else { + titleElement=tmp.toElement(); + } + Q_ASSERT(!titleElement.isNull()); + + // Get title element content (or create) + QDomText titleText; + tmp=titleElement.firstChild(); + if (tmp.isNull()) { + titleText=element.ownerDocument().createTextNode(""); + titleElement.appendChild(titleText); + } else { + titleText=tmp.toText(); + } + Q_ASSERT(!titleText.isNull()); + + // Set title (at last!) + titleText.setData(dialog.title()); + + KBookmarkGroup group=bookmark.parentGroup(); + d->mManager->emitChanged(group); +} + + +void BookmarkViewController::deleteCurrentBookmark() { + BookmarkItem* item=static_cast( d->mListView->currentItem() ); + Q_ASSERT(item); + if (!item) return; + KBookmark bookmark=item->mBookmark; + + QString msg; + QString title; + if (bookmark.isGroup()) { + msg=i18n("Are you sure you want to delete the bookmark folder %1?
This will delete the folder and all the bookmarks in it.") + .arg(bookmark.text()); + title=i18n("Delete Bookmark &Folder"); + } else { + msg=i18n("Are you sure you want to delete the bookmark %1?") + .arg(bookmark.text()); + title=i18n("Delete &Bookmark"); + } + + int response=KMessageBox::warningContinueCancel(d->mListView, + "" + msg + "", title, + KGuiItem(title, "editdelete") + ); + if (response==KMessageBox::Cancel) return; + + KBookmarkGroup group=bookmark.parentGroup(); + group.deleteBookmark(bookmark); + d->mManager->emitChanged(group); +} + + +} // namespace diff --git a/src/app/bookmarkviewcontroller.h b/src/app/bookmarkviewcontroller.h new file mode 100644 index 0000000..bdc8050 --- /dev/null +++ b/src/app/bookmarkviewcontroller.h @@ -0,0 +1,93 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2005 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef BOOKMARKVIEWCONTROLLER_H +#define BOOKMARKVIEWCONTROLLER_H + +// Qt +#include + +// KDE +#include +#include + +class QDragMoveEvent; +class QDropEvent; +class QListViewItem; +class QPoint; +class KBookmarkManager; +class KURL; + +namespace Gwenview { + + +/** + * A listview on which the user can drop urls + */ +class URLDropListView : public KListView { +Q_OBJECT +public: + URLDropListView(QWidget* parent); + +signals: + void urlDropped(QDropEvent*, const KURL::List&); + +protected: + virtual void contentsDragMoveEvent(QDragMoveEvent* event); + virtual void contentsDropEvent(QDropEvent* event); +}; + + +class BookmarkViewController : public QObject { +Q_OBJECT +public: + BookmarkViewController(QWidget*); + ~BookmarkViewController(); + + void init(KBookmarkManager*); + + QWidget* widget() const; + +signals: + void openURL(const KURL&); + +public slots: + void setURL(const KURL&); + +private slots: + void slotOpenBookmark(QListViewItem*); + void fill(); + void slotContextMenu(QListViewItem*); + void slotURLDropped(QDropEvent*, const KURL::List&); + void slotBookmarkDroppedURL(); + void bookmarkCurrentURL(); + void addBookmarkGroup(); + void editCurrentBookmark(); + void deleteCurrentBookmark(); + +private: + struct Private; + Private* d; +}; + + +} // namespace +#endif + diff --git a/src/app/configdialog.cpp b/src/app/configdialog.cpp new file mode 100644 index 0000000..571b6d6 --- /dev/null +++ b/src/app/configdialog.cpp @@ -0,0 +1,306 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +// kate: indent-mode csands; indent-width 4; replace-tabs-save off; replace-tabs off; replace-trailing-space-save off; space-indent off; tabs-indents on; tab-width 4; +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Qt +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +// KIPI +#ifdef GV_HAVE_KIPI +#include +#endif + +// Local +#include "configfileoperationspage.h" +#include "configfullscreenpage.h" +#include "configimagelistpage.h" +#include "configimageviewpage.h" +#include "configmiscpage.h" +#include "configslideshowpage.h" +#include "gvcore/captionformatter.h" +#include "gvcore/filethumbnailview.h" +// This path is different because it's a generated file, so it's stored in builddir +#include <../gvcore/miscconfig.h> +#include <../gvcore/slideshowconfig.h> +#include <../gvcore/fileoperationconfig.h> +#include <../gvcore/fullscreenconfig.h> +#include <../gvcore/imageviewconfig.h> +#include <../gvcore/fileviewconfig.h> +#include "gvcore/thumbnailloadjob.h" + +#include "configdialog.moc" +namespace Gwenview { + +typedef QValueList ConfigManagerList; + +class ConfigDialogPrivate { +public: + ConfigImageViewPage* mImageViewPage; + ConfigImageListPage* mImageListPage; + ConfigFullScreenPage* mFullScreenPage; + ConfigFileOperationsPage* mFileOperationsPage; + ConfigMiscPage* mMiscPage; + ConfigSlideshowPage* mSlideShowPage; +#ifdef GV_HAVE_KIPI + KIPI::ConfigWidget* mKIPIConfigWidget; +#endif + + ConfigManagerList mManagers; +}; + + +// Two helper functions to create the config pages +template +void addConfigPage(KDialogBase* dialog, T* content, const QString& header, const QString& name, const char* iconName) { + QFrame* page=dialog->addPage(name, header, BarIcon(iconName, 32)); + content->reparent(page, QPoint(0,0)); + QVBoxLayout* layout=new QVBoxLayout(page, 0, KDialog::spacingHint()); + layout->addWidget(content); + layout->addStretch(); +} + +template +T* addConfigPage(KDialogBase* dialog, const QString& header, const QString& name, const char* iconName) { + T* content=new T; + addConfigPage(dialog, content, header, name, iconName); + return content; +} + + +ConfigDialog::ConfigDialog(QWidget* parent, KIPI::PluginLoader* pluginLoader) +: KDialogBase( + KDialogBase::IconList, + i18n("Configure"), + KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::Apply, + KDialogBase::Ok, + parent, + "ConfigDialog", + true, + true) +{ + d=new ConfigDialogPrivate; + + // Create dialog pages + d->mImageListPage = addConfigPage( + this, i18n("Configure Image List"), i18n("Image List"), "view_icon"); + d->mManagers << new KConfigDialogManager(d->mImageListPage, FileViewConfig::self()); + + d->mImageViewPage = addConfigPage( + this, i18n("Configure Image View"), i18n("Image View"), "looknfeel"); + d->mManagers << new KConfigDialogManager(d->mImageViewPage, ImageViewConfig::self()); + + d->mFullScreenPage = addConfigPage( + this, i18n("Configure Full Screen Mode"), i18n("Full Screen"), "window_fullscreen"); + d->mManagers << new KConfigDialogManager(d->mFullScreenPage, FullScreenConfig::self()); + + d->mFileOperationsPage = addConfigPage( + this, i18n("Configure File Operations"), i18n("File Operations"), "folder"); + d->mManagers << new KConfigDialogManager(d->mFileOperationsPage, FileOperationConfig::self()); + + d->mSlideShowPage = addConfigPage( + this, i18n("SlideShow"), i18n("SlideShow"), "slideshow_play"); + d->mManagers << new KConfigDialogManager(d->mSlideShowPage, SlideShowConfig::self()); + +#ifdef GV_HAVE_KIPI + Q_ASSERT(pluginLoader); + d->mKIPIConfigWidget = pluginLoader->configWidget(this); + addConfigPage( + this, d->mKIPIConfigWidget, i18n("Configure KIPI Plugins"), i18n("KIPI Plugins"), "kipi"); +#else + // Avoid "unused parameter" warning + pluginLoader=pluginLoader; +#endif + + d->mMiscPage = addConfigPage( + this, i18n("Miscellaneous Settings"), i18n("Misc"), "gear"); + d->mManagers << new KConfigDialogManager(d->mMiscPage, MiscConfig::self()); + // Read config, because the modified behavior might have changed + MiscConfig::self()->readConfig(); + + // Image List tab + int details=FileViewConfig::thumbnailDetails(); + d->mImageListPage->mShowFileName->setChecked(details & FileThumbnailView::FILENAME); + d->mImageListPage->mShowFileDate->setChecked(details & FileThumbnailView::FILEDATE); + d->mImageListPage->mShowFileSize->setChecked(details & FileThumbnailView::FILESIZE); + d->mImageListPage->mShowImageSize->setChecked(details & FileThumbnailView::IMAGESIZE); + + connect(d->mImageListPage->mCalculateCacheSize,SIGNAL(clicked()), + this,SLOT(calculateCacheSize())); + connect(d->mImageListPage->mEmptyCache,SIGNAL(clicked()), + this,SLOT(emptyCache())); + + // Image View tab + d->mImageViewPage->mMouseWheelGroup->setButton(ImageViewConfig::mouseWheelScroll()?1:0); + + // Full Screen tab + QTextEdit* edit=d->mFullScreenPage->kcfg_osdFormat; + edit->setMaximumHeight(edit->fontMetrics().height()*3); + connect(edit, SIGNAL(textChanged()), SLOT(updateOSDPreview()) ); + + // File Operations tab + d->mFileOperationsPage->kcfg_destDir->fileDialog()->setMode( + static_cast(KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly)); + + d->mFileOperationsPage->mDeleteGroup->setButton(FileOperationConfig::deleteToTrash()?1:0); + + ConfigManagerList::Iterator it(d->mManagers.begin()); + for (;it!=d->mManagers.end(); ++it) { + (*it)->updateWidgets(); + } + updateOSDPreview(); +} + + + +ConfigDialog::~ConfigDialog() { + delete d; +} + + +void ConfigDialog::slotOk() { + slotApply(); + accept(); +} + + +void ConfigDialog::slotApply() { + bool needSignal=false; + + // Image List tab + int details= + (d->mImageListPage->mShowFileName->isChecked() ? FileThumbnailView::FILENAME : 0) + | (d->mImageListPage->mShowFileDate->isChecked() ? FileThumbnailView::FILEDATE : 0) + | (d->mImageListPage->mShowFileSize->isChecked() ? FileThumbnailView::FILESIZE : 0) + | (d->mImageListPage->mShowImageSize->isChecked() ? FileThumbnailView::IMAGESIZE : 0) + ; + if (details!=FileViewConfig::thumbnailDetails()) { + FileViewConfig::setThumbnailDetails(details); + needSignal=true; + } + + // Image View tab + ImageViewConfig::setMouseWheelScroll( + d->mImageViewPage->mMouseWheelGroup->selected()==d->mImageViewPage->mMouseWheelScroll); + + // File Operations tab + FileOperationConfig::setDeleteToTrash( + d->mFileOperationsPage->mDeleteGroup->selected()==d->mFileOperationsPage->mDeleteToTrash); + + // KIPI tab +#ifdef GV_HAVE_KIPI + d->mKIPIConfigWidget->apply(); +#endif + + ConfigManagerList::Iterator it(d->mManagers.begin()); + for (;it!=d->mManagers.end(); ++it) { + if ((*it)->hasChanged()) { + needSignal=true; + } + (*it)->updateSettings(); + } + if (needSignal) { + emit settingsChanged(); + } +} + + +void ConfigDialog::calculateCacheSize() { + KURL url; + url.setPath(ThumbnailLoadJob::thumbnailBaseDir()); + unsigned long size=KDirSize::dirSize(url); + KMessageBox::information( this,i18n("Cache size is %1").arg(KIO::convertSize(size)) ); +} + + +void ConfigDialog::updateOSDPreview() { + CaptionFormatter formatter; + KURL url; + url.setPath(i18n("/path/to/some/image.jpg")); + formatter.mPath=url.path(); + formatter.mFileName=url.fileName(); + formatter.mComment=i18n("A comment"); + formatter.mImageSize=QSize(1600, 1200); + formatter.mPosition=4; + formatter.mCount=12; + formatter.mAperture="F2.8"; + formatter.mExposureTime="1/60 s"; + formatter.mIso="100"; + formatter.mFocalLength="8.88 mm"; + + QString txt=formatter.format( d->mFullScreenPage->kcfg_osdFormat->text() ); + d->mFullScreenPage->mOSDPreviewLabel->setText(txt); +} + + +void ConfigDialog::emptyCache() { + QString dir=ThumbnailLoadJob::thumbnailBaseDir(); + + if (!QFile::exists(dir)) { + KMessageBox::information( this,i18n("Cache is already empty.") ); + return; + } + + int response=KMessageBox::warningContinueCancel(this, + "" + i18n("Are you sure you want to empty the thumbnail cache?" + " This will delete the folder %1.").arg(QStyleSheet::escape(dir)) + "", + QString::null, + KStdGuiItem::del()); + + if (response==KMessageBox::Cancel) return; + + KURL url; + url.setPath(dir); + if (KIO::NetAccess::del(url, topLevelWidget()) ) { + KMessageBox::information( this,i18n("Cache emptied.") ); + } +} + + +void ConfigDialog::onCacheEmptied(KIO::Job* job) { + if ( job->error() ) { + job->showErrorDialog(this); + return; + } + KMessageBox::information( this,i18n("Cache emptied.") ); +} + +} // namespace diff --git a/src/app/configdialog.h b/src/app/configdialog.h new file mode 100644 index 0000000..58a479a --- /dev/null +++ b/src/app/configdialog.h @@ -0,0 +1,65 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +// kate: indent-mode csands; indent-width 4; replace-tabs-save off; replace-tabs off; replace-trailing-space-save off; space-indent off; tabs-indents on; tab-width 4; +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef CONFIGDIALOG_H +#define CONFIGDIALOG_H + +// KDE +#include + +// KIPI +namespace KIPI { +class PluginLoader; +} + + +namespace Gwenview { + +class ConfigDialogPrivate; + +class ConfigDialog : public KDialogBase { +Q_OBJECT +public: + ConfigDialog(QWidget*, KIPI::PluginLoader*); + ~ConfigDialog(); + +signals: + void settingsChanged(); + +protected slots: + void slotOk(); + void slotApply(); + +private slots: + void updateOSDPreview(); + void calculateCacheSize(); + void emptyCache(); + void onCacheEmptied(KIO::Job*); + +private: + ConfigDialogPrivate* d; +}; + + + +} // namespace +#endif + diff --git a/src/app/configfileoperationspage.ui b/src/app/configfileoperationspage.ui new file mode 100644 index 0000000..b3d2f39 --- /dev/null +++ b/src/app/configfileoperationspage.ui @@ -0,0 +1,173 @@ + +ConfigFileOperationsPage + + + ConfigFileOperationsPage + + + + 0 + 0 + 308 + 252 + + + + Configure File Operations + + + + unnamed + + + 0 + + + + textLabel2_2_2 + + + <b>Moving & Copying Files</b> + + + + + kcfg_confirmCopy + + + Show copy dialog + + + + + kcfg_confirmMove + + + Show move dialog + + + + + Layout2 + + + + unnamed + + + 0 + + + 6 + + + + TextLabel2 + + + Default destination folder: + + + + + kcfg_destDir + + + + 3 + 5 + 0 + 0 + + + + + + + + spacer10_2_2_2 + + + Vertical + + + Fixed + + + + 21 + 16 + + + + + + textLabel2_2 + + + <b>Deleting Files</b> + + + + + kcfg_confirmDelete + + + Ask for confirmation + + + + + mDeleteGroup + + + NoFrame + + + + + + + unnamed + + + 0 + + + 6 + + + + mDeleteToTrash + + + Move deleted files to the trash + + + 1 + + + + + mReallyDelete + + + Really delete files (dangerous) + + + 0 + + + + + + + + + + + kurlrequester.h + klineedit.h + kpushbutton.h + + diff --git a/src/app/configfullscreenpage.ui b/src/app/configfullscreenpage.ui new file mode 100644 index 0000000..c0eaeba --- /dev/null +++ b/src/app/configfullscreenpage.ui @@ -0,0 +1,144 @@ + +ConfigFullScreenPage + + + ConfigFullScreenPage + + + + 0 + 0 + 516 + 411 + + + + Configure Full Screen Mode + + + + unnamed + + + 0 + + + + kcfg_showBusyPtr + + + Show busy mouse pointer when loading an image + + + true + + + + + spacer10_2_3_2 + + + Vertical + + + Fixed + + + + 21 + 16 + + + + + + textLabel3_2 + + + <b>On Screen Display</b> + + + + + kcfg_osdFormat + + + PlainText + + + %f - %n/%N +%c + + + WidgetWidth + + + AutoNone + + + + + textLabel2 + + + Preview: + + + + + mOSDPreviewLabel + + + LineEditPanel + + + Sunken + + + file.jpg - 1024x768 +The file comment + + + + + textLabel1 + + + <qt> +You can use the following keywords to format the On Screen Display: +<ul> +<li>%f: filename</li> +<li>%p: filepath</li> +<li>%c: comment</li> +<li>%r: resolution</li> +<li>%n: current image position</li> +<li>%N: image count</li> +<li>%a: aperture</li> +<li>%t: exposure time</li> +<li>%i: iso</li> +<li>%l: focal length</li> +</ul> +</qt> + + + + + spacer10_2_3 + + + Vertical + + + Expanding + + + + 21 + 18 + + + + + + + diff --git a/src/app/configimagelistpage.ui b/src/app/configimagelistpage.ui new file mode 100644 index 0000000..7b378c7 --- /dev/null +++ b/src/app/configimagelistpage.ui @@ -0,0 +1,294 @@ + +ConfigImageListPage + + + ConfigImageListPage + + + + 0 + 0 + 352 + 437 + + + + Configure Image List + + + + unnamed + + + 0 + + + + kcfg_showDirs + + + Show folders and archives + + + + + spacer10_2 + + + Vertical + + + Fixed + + + + 21 + 16 + + + + + + textLabel1_2_2 + + + + 1 + 5 + 0 + 0 + + + + <b>Thumbnail View</b> + + + + + Layout6 + + + + unnamed + + + 0 + + + 6 + + + + TextLabel1 + + + + 1 + 1 + 0 + 0 + + + + Margin between thumbnails: + + + + + + + + kcfg_thumbnailMarginSize + + + + 0 + 0 + 0 + 0 + + + + UpDownArrows + + + 50 + + + 2 + + + 1 + + + + + Spacer7 + + + Horizontal + + + Expanding + + + + 20 + 0 + + + + + + + + textLabel1 + + + Information to display in the thumbnail text: + + + + + layout6 + + + + unnamed + + + + spacer7 + + + Horizontal + + + Fixed + + + + 21 + 20 + + + + + + mShowFileName + + + File name + + + + + mShowImageSize + + + Image size + + + + + mShowFileSize + + + File size + + + + + mShowFileDate + + + File date + + + + + + + spacer10 + + + Vertical + + + Fixed + + + + 21 + 16 + + + + + + textLabel1_2 + + + + 1 + 5 + 0 + 0 + + + + <b>Thumbnail Cache</b> + + + + + kcfg_storeThumbnailsInCache + + + Store thumbnails in cache + + + + + kcfg_deleteCacheOnExit + + + Automatically empty thumbnail cache on exit + + + + + layout7 + + + + unnamed + + + 0 + + + 6 + + + + mCalculateCacheSize + + + Calculate Cache Size + + + + + mEmptyCache + + + Empty Cache + + + + + + + + diff --git a/src/app/configimageviewpage.ui b/src/app/configimageviewpage.ui new file mode 100644 index 0000000..6abbf7b --- /dev/null +++ b/src/app/configimageviewpage.ui @@ -0,0 +1,330 @@ + +ConfigImageViewPage + + + ConfigImageViewPage + + + + 0 + 0 + 387 + 404 + + + + Configure Image View + + + + unnamed + + + 0 + + + + kcfg_enlargeSmallImages + + + Enlarge small images when auto &zoom is activated + + + + + textLabel1 + + + Background color: + + + + + kcfg_backgroundColor + + + + + + + + spacer2 + + + Horizontal + + + Expanding + + + + 181 + 21 + + + + + + textLabel1_3_2 + + + <b>Smoothing</b> + + + + + layout4 + + + + unnamed + + + + kcfg_smoothAlgorithm + + + + 1 + 5 + 0 + 0 + + + + NoFrame + + + + + + + unnamed + + + 0 + + + + mSmoothNone + + + None + + + true + + + 0 + + + + + mSmoothFast + + + Fast + + + 1 + + + + + mSmoothNormal + + + Normal + + + 2 + + + + + mSmoothBest + + + Best + + + 3 + + + + + + + line1 + + + VLine + + + Sunken + + + Vertical + + + + + frame3 + + + + 7 + 5 + 0 + 0 + + + + NoFrame + + + Raised + + + + unnamed + + + 0 + + + + kcfg_delayedSmoothing + + + false + + + Delayed smoothing + + + + + textLabel1_4 + + + false + + + 3 + + + Using this option, Gwenview will display the image as fast as possible, and smooth it after a short delay. +Use this option if your computer is not very fast. + + + WordBreak|AlignTop + + + mDelayedSmoothing + + + + + + + + + spacer10_2_3_2 + + + Vertical + + + Fixed + + + + 21 + 16 + + + + + + mMouseWheelGroup + + + NoFrame + + + + + + + unnamed + + + 0 + + + 6 + + + + mMouseWheelScroll + + + Scroll current image + + + 1 + + + + + mMouseWheelBrowse + + + Browse image list + + + 0 + + + + + + + textLabel1_3 + + + <b>Mouse Wheel Behavior over Image</b> + + + + + kcfg_showScrollBars + + + Show scroll bars + + + + + + + + + mSmoothNone + toggled(bool) + kcfg_delayedSmoothing + setDisabled(bool) + + + mSmoothNone + toggled(bool) + textLabel1_4 + setDisabled(bool) + + + + + kcolorbutton.h + + diff --git a/src/app/configmiscpage.ui b/src/app/configmiscpage.ui new file mode 100644 index 0000000..e4768f2 --- /dev/null +++ b/src/app/configmiscpage.ui @@ -0,0 +1,204 @@ + +ConfigMiscPage + + + ConfigMiscPage + + + + 0 + 0 + 457 + 303 + + + + Miscellaneous Settings + + + + unnamed + + + 0 + + + + textLabel1_2_2_2 + + + What to do when leaving a modified image + + + + + kcfg_modifiedBehavior + + + NoFrame + + + + + + + unnamed + + + + mModifyAsk + + + Ask + + + true + + + 0 + + + + + mModifySave + + + Save silently + + + 1 + + + + + mModifyDiscard + + + Discard changes + + + 2 + + + + + + + spacer1 + + + Vertical + + + Fixed + + + + 20 + 24 + + + + + + kcfg_autoRotateImages + + + Automatically rotate images on load + + + true + + + + + spacer1_2 + + + Vertical + + + Fixed + + + + 20 + 24 + + + + + + textLabel1 + + + Which settings should be remembered next time you start Gwenview + + + + + layout1 + + + + unnamed + + + + spacer6 + + + Horizontal + + + Fixed + + + + 11 + 20 + + + + + + kcfg_rememberURL + + + Last opened URL + + + + + kcfg_rememberFilter + + + State of filter + + + + + + + + + + spacer5 + + + Vertical + + + Expanding + + + + 21 + 41 + + + + + + + diff --git a/src/app/configslideshowpage.ui b/src/app/configslideshowpage.ui new file mode 100644 index 0000000..cb06835 --- /dev/null +++ b/src/app/configslideshowpage.ui @@ -0,0 +1,134 @@ + +ConfigSlideshowPage + + + ConfigSlideshowPage + + + + 0 + 0 + 494 + 148 + + + + + unnamed + + + 0 + + + + kcfg_loop + + + Loop + + + + + kcfg_random + + + Show images in random order + + + + + kcfg_fullscreen + + + Start in fullscreen mode + + + true + + + + + kcfg_stopAtEnd + + + Stop on the last image of the folder + + + By default, if you start the slideshow from the middle of a folder, the slideshow will show all images after the start image, then all images before the start image. + +When this option is enabled, the slideshow will stop on the last image of the folder. + + + + + mDelayLabel + + + + 1 + 1 + 0 + 0 + + + + Delay between images (in seconds): + + + + + + + + Spacer7_2 + + + Horizontal + + + Expanding + + + + 180 + 20 + + + + + + kcfg_delay + + + 100 + + + 0 + + + 0.1 + + + false + + + 2 + + + + + + + + + kcfg_loop + toggled(bool) + kcfg_stopAtEnd + setDisabled(bool) + + + + + knuminput.h + + diff --git a/src/app/dirviewcontroller.cpp b/src/app/dirviewcontroller.cpp new file mode 100644 index 0000000..c5fc538 --- /dev/null +++ b/src/app/dirviewcontroller.cpp @@ -0,0 +1,143 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +// kate: indent-mode csands; indent-width 4; replace-tabs-save off; replace-tabs off; replace-trailing-space-save off; space-indent off; tabs-indents on; tab-width 4; +/* +Gwenview - A simple image viewer for KDE +Copyright 2005 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Self +#include "dirviewcontroller.moc" + +// Qt +#include + +// KDE +#include +#include +#include +#include +#include + +// Local +#include +#include + + +namespace Gwenview { + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +struct DirViewController::Private { + TreeView* mTreeView; +}; + + +DirViewController::DirViewController(QWidget* parent) +: QObject(parent) +{ + d=new Private; + + d->mTreeView=new TreeView(parent); + + connect(d->mTreeView, SIGNAL(selectionChanged(QListViewItem*)), + this, SLOT(slotTreeViewSelectionChanged(QListViewItem*)) ); + + connect(d->mTreeView, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotTreeViewContextMenu(KListView*, QListViewItem*, const QPoint&)) ); +} + + +DirViewController::~DirViewController() { + delete d; +} + + +QWidget* DirViewController::widget() const { + return d->mTreeView; +} + + +void DirViewController::setURL(const KURL& url) { + d->mTreeView->setURL(url); +} + + +void DirViewController::slotTreeViewSelectionChanged(QListViewItem* item) { + if (!item) return; + LOG(d->mTreeView->currentURL()); + emit urlChanged(d->mTreeView->currentURL()); +} + + +void DirViewController::slotTreeViewContextMenu(KListView*, QListViewItem*, const QPoint& pos) { + QPopupMenu menu(d->mTreeView); + menu.insertItem(SmallIcon("folder_new"),i18n("New Folder..."),this,SLOT(makeDir())); + menu.insertSeparator(); + menu.insertItem(i18n("Rename..."),this,SLOT(renameDir())); + menu.insertItem(SmallIcon("editdelete"),i18n("Delete"),this,SLOT(removeDir())); + menu.insertSeparator(); + menu.insertItem(i18n("Properties"),this,SLOT(showPropertiesDialog())); + + menu.exec(pos); +} + + +void DirViewController::makeDir() { + if (!d->mTreeView->currentItem()) return; + FileOperation::makeDir(d->mTreeView->currentURL(), d->mTreeView, this, SLOT(slotDirMade()) ); +} + + +void DirViewController::slotDirMade() { + if (!d->mTreeView->currentItem()) return; + d->mTreeView->currentItem()->setOpen(true); +} + + +void DirViewController::renameDir() { + if (!d->mTreeView->currentItem()) return; + FileOperation::rename(d->mTreeView->currentURL(), d->mTreeView); +} + + +void DirViewController::removeDir() { + if (!d->mTreeView->currentItem()) return; + + KURL::List list; + list << d->mTreeView->currentURL(); + FileOperation::del(list, d->mTreeView); + + QListViewItem* item=d->mTreeView->currentItem(); + if (!item) return; + item=item->parent(); + if (!item) return; + d->mTreeView->setCurrentItem(item); +} + + +void DirViewController::showPropertiesDialog() { + (void)new KPropertiesDialog(d->mTreeView->currentURL(), d->mTreeView); +} + +} // namespace diff --git a/src/app/dirviewcontroller.h b/src/app/dirviewcontroller.h new file mode 100644 index 0000000..129cc8f --- /dev/null +++ b/src/app/dirviewcontroller.h @@ -0,0 +1,71 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +// kate: indent-mode csands; indent-width 4; replace-tabs-save off; replace-tabs off; replace-trailing-space-save off; space-indent off; tabs-indents on; tab-width 4; +/* +Gwenview - A simple image viewer for KDE +Copyright 2005 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef DIRVIEWCONTROLLER_H +#define DIRVIEWCONTROLLER_H + +// Qt +#include "qobject.h" + +class QListViewItem; +class QPoint; +class QWidget; +class KListView; +class KURL; + +namespace KIO { +class Job; +} + +namespace Gwenview { + +class DirViewController : public QObject { + Q_OBJECT +public: + DirViewController(QWidget* parent); + virtual ~DirViewController(); + QWidget* widget() const; + +public slots: + void setURL(const KURL&); + +signals: + void urlChanged(const KURL&); + void urlRenamed(const KURL& from, const KURL& to); + +private: + struct Private; + Private* d; + +private slots: + void slotTreeViewSelectionChanged(QListViewItem*); + void slotTreeViewContextMenu(KListView*, QListViewItem*, const QPoint&); + + void makeDir(); + void slotDirMade(); + void renameDir(); + void removeDir(); + void showPropertiesDialog(); +}; + +} // namespace + +#endif /* DIRVIEWCONTROLLER_H */ diff --git a/src/app/gwenviewui.rc b/src/app/gwenviewui.rc new file mode 100644 index 0000000..6e165ad --- /dev/null +++ b/src/app/gwenviewui.rc @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + &View + + + + + + + + + + + + + + &Colors + + + + + + + + + + + + + + + + + + &Go + + + + + + + + + + + + + + + + + + + + &Plugins + + Images + + + + Effects + + + + Tools + + + + Batch Processing + + + + Import + + + + Export + + + + Collections + + + + + &Window + + + + + + + + Main Toolbar + + + + + + + + Location Toolbar + + + + + + + + + + + + + diff --git a/src/app/history.cpp b/src/app/history.cpp new file mode 100644 index 0000000..d9cb30e --- /dev/null +++ b/src/app/history.cpp @@ -0,0 +1,137 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau +Copyright 2003 Tudor Calin + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// KDE +#include +#include +#include +#include +#include +#include + +// Local +#include "history.moc" +namespace Gwenview { + + +const unsigned int MAX_HISTORY_SIZE=12; + +History::History(KActionCollection* actionCollection) { + mPosition=mHistoryList.end(); + mMovingInHistory=false; + + // Actions + QPair backForward = KStdGuiItem::backAndForward(); + mGoBack=new KToolBarPopupAction(backForward.first, + KStdAccel::shortcut(KStdAccel::Back), + this, SLOT(goBack()), actionCollection, "go_back"); + mGoForward=new KToolBarPopupAction(backForward.second, + KStdAccel::shortcut(KStdAccel::Forward), + this, SLOT(goForward()), actionCollection, "go_forward"); + + // Connections + connect(mGoBack->popupMenu(),SIGNAL(activated(int)), + this,SLOT(goBackTo(int)) ); + connect(mGoForward->popupMenu(),SIGNAL(activated(int)), + this,SLOT(goForwardTo(int)) ); + + connect(mGoBack->popupMenu(), SIGNAL(aboutToShow()), + this, SLOT(fillGoBackMenu()) ); + connect(mGoForward->popupMenu(), SIGNAL(aboutToShow()), + this, SLOT(fillGoForwardMenu()) ); +} + + +History::~History() { +} + + +void History::addURLToHistory(const KURL& url2) { + KURL url( url2 ); + url.setFileName( QString::null ); + if (!mMovingInHistory) { + if (mPosition!=mHistoryList.end() && url.equals(*mPosition, true)) return; + + // Drop everything after current + HistoryList::iterator it=mPosition; + ++it; + mHistoryList.erase(it, mHistoryList.end()); + + mHistoryList.append(url); + if(mHistoryList.count()==MAX_HISTORY_SIZE) mHistoryList.pop_front(); + mPosition=mHistoryList.fromLast(); + } + + mGoBack->setEnabled(mPosition!=mHistoryList.begin()); + mGoForward->setEnabled(mPosition!=mHistoryList.fromLast()); +} + + +void History::fillGoBackMenu() { + QPopupMenu* menu=mGoBack->popupMenu(); + menu->clear(); + HistoryList::ConstIterator it; + + int pos=1; + for(it=mHistoryList.begin(); it!=mPosition; ++it, ++pos) { + menu->insertItem( (*it).prettyURL(-1), pos, 0); + } +} + +void History::fillGoForwardMenu() { + QPopupMenu* menu=mGoForward->popupMenu(); + menu->clear(); + HistoryList::ConstIterator it=mPosition; + ++it; + + int pos=1; + for(; it!=mHistoryList.end(); ++it, ++pos) { + menu->insertItem( (*it).prettyURL(-1), pos, -1); + } +} + +void History::goBack() { + goBackTo(1); +} + + +void History::goForward() { + goForwardTo(1); +} + + +void History::goBackTo(int id) { + for (;id>0; --id) --mPosition; + mMovingInHistory=true; + emit urlChanged(*mPosition); + mMovingInHistory=false; +} + + +void History::goForwardTo(int id) { + for (;id>0; --id) ++mPosition; + mMovingInHistory=true; + emit urlChanged(*mPosition); + mMovingInHistory=false; +} + +} // namespace diff --git a/src/app/history.h b/src/app/history.h new file mode 100644 index 0000000..38e912d --- /dev/null +++ b/src/app/history.h @@ -0,0 +1,71 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau +Copyright 2003 Tudor Calin + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef HISTORY_H +#define HISTORY_H + +// Qt +#include +#include + +// KDE +#include + +class KToolBarPopupAction; +class KActionCollection; + +typedef QValueList HistoryList; + +namespace Gwenview { +class History : public QObject { +Q_OBJECT + +public: + History(KActionCollection*); + ~History(); + +signals: + void urlChanged(const KURL&); + +public slots: + void addURLToHistory(const KURL&); + +private: + KToolBarPopupAction* mGoBack; + KToolBarPopupAction* mGoForward; + HistoryList mHistoryList; + HistoryList::Iterator mPosition; + bool mMovingInHistory; + +private slots: + void fillGoBackMenu(); + void fillGoForwardMenu(); + void goBack(); + void goForward(); + void goBackTo(int); + void goForwardTo(int); +}; + +} // namespace +#endif + + + diff --git a/src/app/kipiinterface.cpp b/src/app/kipiinterface.cpp new file mode 100644 index 0000000..94b2455 --- /dev/null +++ b/src/app/kipiinterface.cpp @@ -0,0 +1,224 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include +#ifdef GV_HAVE_KIPI + +// Qt +#include +#include +#include + +// KDE +#include +#include +#include +#include + +// KIPI +#include +#include + +// Local +#include "gvcore/archive.h" +#include "gvcore/cache.h" +#include "gvcore/fileviewbase.h" +#include "gvcore/fileviewcontroller.h" +#include "imageutils/jpegcontent.h" +#include "kipiinterface.moc" +namespace Gwenview { + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +class ImageCollection : public KIPI::ImageCollectionShared { +public: + ImageCollection(KURL dirURL, const QString& name, const KURL::List& images) + : KIPI::ImageCollectionShared() + , mDirURL(dirURL) + , mName(name) + , mImages(images) {} + + QString name() { return mName; } + QString comment() { return QString::null; } + KURL::List images() { return mImages; } + KURL uploadRoot() { return KURL("/"); } + KURL uploadPath() { return mDirURL; } + QString uploadRootName() { return "/"; } + bool isDirectory() { return true; } + +private: + KURL mDirURL; + QString mName; + KURL::List mImages; +}; + + + +class ImageInfo : public KIPI::ImageInfoShared { + static const QRegExp sExtensionRE; +public: + ImageInfo(KIPI::Interface* interface, const KURL& url) : KIPI::ImageInfoShared(interface, url) {} + + QString title() { + QString txt=_url.fileName(); + txt.replace("_", " "); + txt.replace(sExtensionRE, ""); + return txt; + } + + QString description() { + if (!_url.isLocalFile()) return QString::null; + + ImageUtils::JPEGContent content; + bool ok=content.load(_url.path()); + if (!ok) return QString::null; + + return content.comment(); + } + + void setDescription(const QString&) {} + + QMap attributes() { + return QMap(); + } + + void clearAttributes() {} + + void addAttributes(const QMap&) {} +}; + +const QRegExp ImageInfo::sExtensionRE("\\.[a-z0-9]+$", false /*caseSensitive*/); + + +struct KIPIInterfacePrivate { + FileViewController* mFileView; +}; + + +KIPIInterface::KIPIInterface( QWidget* parent, FileViewController* fileView) +:KIPI::Interface(parent, "Gwenview kipi interface") { + d=new KIPIInterfacePrivate; + d->mFileView=fileView; + + connect(d->mFileView, SIGNAL(selectionChanged()), + this, SLOT(slotSelectionChanged()) ); + + connect(d->mFileView, SIGNAL(completed()), + this, SLOT(slotDirectoryChanged()) ); +// delay a bit, so that it's called after loadPlugins() + QTimer::singleShot( 0, this, SLOT( init())); +} + + +KIPIInterface::~KIPIInterface() { + delete d; +} + + +void KIPIInterface::init() { + slotDirectoryChanged(); + slotSelectionChanged(); +} + +KIPI::ImageCollection KIPIInterface::currentAlbum() { + LOG(""); + KURL::List list; + KFileItemListIterator it( *d->mFileView->currentFileView()->items() ); + for ( ; it.current(); ++it ) { + KFileItem* item=it.current(); + if (!Archive::fileItemIsDirOrArchive(item)) { + list.append(it.current()->url()); + } + } + KURL url=d->mFileView->dirURL(); + return KIPI::ImageCollection(new ImageCollection(url, url.fileName(), list)); +} + + +KIPI::ImageCollection KIPIInterface::currentSelection() { + LOG(""); + KURL::List list=d->mFileView->selectedImageURLs(); + KURL url=d->mFileView->dirURL(); + return KIPI::ImageCollection(new ImageCollection(url, i18n("%1 (Selected Images)").arg(url.fileName()), list)); +} + + +QValueList KIPIInterface::allAlbums() { + LOG(""); + QValueList list; + list << currentAlbum() << currentSelection(); + return list; +} + + +KIPI::ImageInfo KIPIInterface::info(const KURL& url) { + LOG(""); + return KIPI::ImageInfo( new ImageInfo(this, url) ); +} + +int KIPIInterface::features() const { + return KIPI::AcceptNewImages; +} + +/** + * KDirLister will pick up the image if necessary, so no updating is needed + * here, it is however necessary to discard caches if the plugin preserves timestamp + */ +bool KIPIInterface::addImage(const KURL& url, QString&) { + Cache::instance()->invalidate( url ); + return true; +} + +void KIPIInterface::delImage(const KURL& url) { + Cache::instance()->invalidate( url ); +} + +// TODO currently KDirWatch doesn't have watching of files in a directory +// implemented, so KDirLister will not inform when a file changes +void KIPIInterface::refreshImages( const KURL::List& urls ) { + for( KURL::List::ConstIterator it = urls.begin(); + it != urls.end(); + ++it ) { + Cache::instance()->invalidate( *it ); + } + d->mFileView->refreshItems( urls ); +} + + +void KIPIInterface::slotSelectionChanged() { + emit selectionChanged(d->mFileView->selectionSize() > 0); +} + + +void KIPIInterface::slotDirectoryChanged() { + emit currentAlbumChanged(d->mFileView->fileCount() > 0); +} + + +} // namespace + +#endif /* GV_HAVE_KIPI */ diff --git a/src/app/kipiinterface.h b/src/app/kipiinterface.h new file mode 100644 index 0000000..c664409 --- /dev/null +++ b/src/app/kipiinterface.h @@ -0,0 +1,62 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef KIPIINTERFACE_H +#define KIPIINTERFACE_H + +#include +#ifdef GV_HAVE_KIPI + +#include +namespace Gwenview { + +class KIPIInterfacePrivate; + +class FileViewController; + +class KIPIInterface :public KIPI::Interface { + Q_OBJECT + +public: + KIPIInterface( QWidget* parent, FileViewController*); + virtual ~KIPIInterface(); + + KIPI::ImageCollection currentAlbum(); + KIPI::ImageCollection currentSelection(); + QValueList allAlbums(); + KIPI::ImageInfo info( const KURL& ); + int features() const; + virtual bool addImage(const KURL&, QString& err); + virtual void delImage( const KURL& ); + virtual void refreshImages( const KURL::List& urls ); + +private: + KIPIInterfacePrivate* d; + +private slots: + void slotSelectionChanged(); + void slotDirectoryChanged(); + void init(); +}; + +#endif /* GV_HAVE_KIPI */ +} // namespace +#endif /* KIPIINTERFACE_H */ + diff --git a/src/app/main.cpp b/src/app/main.cpp new file mode 100644 index 0000000..9fe8cb2 --- /dev/null +++ b/src/app/main.cpp @@ -0,0 +1,163 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2006 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include + +#include +#include +#include +#include +#include + +#include "gvcore/cache.h" +#include "gvcore/fileviewcontroller.h" +#include <../gvcore/fileviewconfig.h> +#include <../gvcore/miscconfig.h> +#include "mainwindow.h" +namespace Gwenview { + +static KCmdLineOptions options[] = { + { "f", I18N_NOOP("Start in fullscreen mode"), 0 }, + { "filter-type ", I18N_NOOP("Filter by file type"), 0 }, + { "filter-name ", I18N_NOOP("Filter by file pattern (*.jpg, 01*...)"), 0 }, + { "filter-from ", I18N_NOOP("Only show files newer or equal to "), 0 }, + { "filter-to ", I18N_NOOP("Only show files older or equal to "), 0 }, + { "+[file or folder]", I18N_NOOP("A starting file or folder"), 0 }, + KCmdLineLastOption +}; + +static const char version[] = "1.4.2"; + + +void applyFilterArgs(KCmdLineArgs* args, FileViewController* controller) { + QString filterType = args->getOption("filter-type"); + QString filterName = args->getOption("filter-name"); + QString filterFrom = args->getOption("filter-from"); + QString filterTo = args->getOption("filter-to"); + // Do nothing if there is no filter + if (filterType.isEmpty() && filterName.isEmpty() + && filterFrom.isEmpty() && filterTo.isEmpty()) + { + return; + } + + QStringList typeList; + typeList << "all" << "images" << "videos"; + int mode = typeList.findIndex(filterType); + if (mode == -1) { + // Default to "all" + controller->setFilterMode(0); + } else { + controller->setFilterMode(mode); + } + + controller->setShowFilterBar( + !filterName.isEmpty() + || !filterFrom.isEmpty() + || !filterTo.isEmpty() ); + + controller->setFilterName(filterName); + + bool ok = false; + QDate date; + if (!filterFrom.isEmpty()) { + date = KGlobal::locale()->readDate(filterFrom, &ok); + if (!ok) { + kdWarning() << "Invalid value for filter-from option\n"; + } + } + controller->setFilterFromDate(date); + + date=QDate(); + if (!filterTo.isEmpty()) { + date = KGlobal::locale()->readDate(filterTo, &ok); + if (!ok) { + kdWarning() << "Invalid value for filter-to option\n"; + } + } + controller->setFilterToDate(date); + + controller->applyFilter(); +} + + +#ifndef __KDE_HAVE_GCC_VISIBILITY +#undef KDE_EXPORT +#define KDE_EXPORT +#endif + +extern "C" +KDE_EXPORT int kdemain (int argc, char *argv[]) { + KAboutData aboutData("gwenview", I18N_NOOP("Gwenview"), + version, I18N_NOOP("An image viewer for KDE"), KAboutData::License_GPL, + "Copyright 2000-2006, The Gwenview developers",0,"http://gwenview.sourceforge.net"); + aboutData.addAuthor("Aurélien Gâteau", I18N_NOOP("Main developer"), "aurelien.gateau@free.fr"); + aboutData.addAuthor("Luboš Luňák", I18N_NOOP("Developer"), "l.lunak@suse.cz"); + + aboutData.addCredit("Frank Becker", I18N_NOOP("Fast JPEG thumbnail generation (v0.13.0)"), "ff@telus.net"); + aboutData.addCredit("Tudor Calin", I18N_NOOP("Address bar (v0.16.0)\nHistory support (v1.0.0)"), "tudor_calin@mymail.ro"); + aboutData.addCredit("Avinash Chopde", I18N_NOOP("File operation patch (v0.9.2)"), "avinash@acm.org"); + aboutData.addCredit("Marco Gazzetta", I18N_NOOP("Fixed crash when trying to generate a thumbnail for a broken JPEG file (v0.16.0)"), "mililani@pobox.com"); + aboutData.addCredit("GeniusR13", I18N_NOOP("Fixed compilation on KDE 3.0 (v0.16.1)"), "geniusr13@gmx.net"); + aboutData.addCredit("Ian Koenig", I18N_NOOP("First RPM spec file"), "iguy@ionsphere.org"); + aboutData.addCredit("Meni Livne", I18N_NOOP("Toolbar layout patch for RTL languages (v0.16.0)"), "livne@kde.org"); + aboutData.addCredit("Angelo Naselli", I18N_NOOP("Printing support (v1.0.0)"), "anaselli@linux.it"); + aboutData.addCredit("Jos van den Oever", I18N_NOOP("File info view (v1.0.0)\nPatch to toggle auto-zoom on click (v1.0.0)"), "jos@vandenoever.info"); + aboutData.addCredit("Jeroen Peters", I18N_NOOP("Configurable mouse wheel behavior (v1.1.1)"), "jpeters@coldmail.nl"); + aboutData.addCredit("Andreas Pfaller", I18N_NOOP("Option to prevent Gwenview from automatically loading the first image of a folder (v0.15.0)"), "apfaller@yahoo.com.au"); + aboutData.addCredit("Renchi Raju", I18N_NOOP("Fixed thumbnail generation to share the thumbnail folder of Konqueror v3 (v0.15.0)"), "renchi@green.tam.uiuc.edu"); + aboutData.addCredit("Michael Spanier", I18N_NOOP("Patch for mouse navigation (v0.7.0)"), "mail@michael-spanier.de"); + aboutData.addCredit("Christian A Strømmen", I18N_NOOP("Integration in Konqueror folder context menu"), "number1@realityx.net"); + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication kapplication; + + if (kapplication.isRestored()) { + RESTORE(MainWindow) + } else { + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + MainWindow *mainWindow = new MainWindow; + applyFilterArgs(args, mainWindow->fileViewController()); + + bool fullscreen=args->isSet("f"); + if (fullscreen) mainWindow->setFullScreen(true); + + KURL url; + if (args->count()>0) { + url=args->url(0); + } else { + if (MiscConfig::rememberURL() && MiscConfig::history().count() > 0) { + url = KURL(MiscConfig::history()[0]); + } else { + url.setPath( QDir::currentDirPath() ); + } + } + mainWindow->openURL(url); + + mainWindow->show(); + } + + return kapplication.exec(); +} + +} // namespace diff --git a/src/app/mainwindow.cpp b/src/app/mainwindow.cpp new file mode 100644 index 0000000..2cd873a --- /dev/null +++ b/src/app/mainwindow.cpp @@ -0,0 +1,1371 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +// kate: indent-mode csands; indent-width 4; replace-tabs-save off; replace-tabs off; replace-trailing-space-save off; space-indent off; tabs-indents on; tab-width 4; +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "mainwindow.moc" + +// Qt +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +// KIPI +#ifdef GV_HAVE_KIPI +#include +#include +#endif + +// Local +#include "bookmarkowner.h" +#include "bookmarkviewcontroller.h" +#include "configdialog.h" +#include "dirviewcontroller.h" +#include "history.h" +#include "metaedit.h" +#include "truncatedtextlabel.h" +#include "vtabwidget.h" + +#include "gvcore/externaltoolcontext.h" +#include "gvcore/externaltoolmanager.h" +#include "gvcore/fileoperation.h" +#include "gvcore/archive.h" +#include "gvcore/captionformatter.h" +#include "gvcore/document.h" +#include "gvcore/externaltooldialog.h" +#include "gvcore/fileviewbase.h" +#include "gvcore/fileviewcontroller.h" +#include "gvcore/imageview.h" +#include "gvcore/imageviewcontroller.h" +#include "gvcore/slideshow.h" +#include "gvcore/printdialog.h" +#include "gvcore/cache.h" +#include "gvcore/thumbnailloadjob.h" +#include <../gvcore/slideshowconfig.h> +#include <../gvcore/fullscreenconfig.h> +#include <../gvcore/fileviewconfig.h> +#include <../gvcore/miscconfig.h> + +#include "config.h" + +#ifdef GV_HAVE_KIPI +#include "kipiinterface.h" +#endif + +namespace Gwenview { + +const char CONFIG_DOCK_GROUP[]="dock"; +const char CONFIG_DIRWIDGET_GROUP[]="dir widget"; +const char CONFIG_PIXMAPWIDGET_GROUP[]="pixmap widget"; +const char CONFIG_CACHE_GROUP[]="cache"; + +const char CONFIG_GWENVIEW_DOCK_VERSION[]="Gwenview version"; + +const char CONFIG_SESSION_URL[] = "url"; + +// This version is here to avoid configuration migration troubles when changes +// are made to the dock behavior +const int GWENVIEW_DOCK_VERSION=2; + +// The timeout before an hint in the statusbar disappear (in msec) +const int HINT_TIMEOUT=10000; + +// How many items should be stored in history +const int HISTORY_MAX_COUNT=20; + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +enum { StackIDBrowse, StackIDView }; + + +static bool urlIsDirectory(QWidget* parent, const KURL& url) { + if( url.filename( false ).isEmpty()) return true; // file:/somewhere/ + // Do direct stat instead of using KIO if the file is local (faster) + if( url.isLocalFile() + && !KIO::probably_slow_mounted( url.path())) { + KDE_struct_stat buff; + if ( KDE_stat( QFile::encodeName(url.path()), &buff ) == 0 ) { + return S_ISDIR( buff.st_mode ); + } + } + KIO::UDSEntry entry; + if( KIO::NetAccess::stat( url, entry, parent)) { + KIO::UDSEntry::ConstIterator it; + for(it=entry.begin();it!=entry.end();++it) { + if ((*it).m_uds==KIO::UDS_FILE_TYPE) { + return S_ISDIR( (*it).m_long ); + } + } + } + return false; +} + + +MainWindow::MainWindow() +: KMainWindow() +#ifdef GV_HAVE_KIPI +, mPluginLoader(0) +#endif +{ + // Backend + mDocument=new Document(this); + mHistory=new History(actionCollection()); + // GUI + createActions(); + createWidgets(); + createLocationToolBar(); + createObjectInteractions(); + + setStandardToolBarMenuEnabled(true); + createGUI("gwenviewui.rc", false); + + createConnections(); + mWindowListActions.setAutoDelete(true); + updateWindowActions(); + KMainWindow::applyMainWindowSettings(KGlobal::config(), "MainWindow"); +} + + +void MainWindow::setFullScreen(bool value) { + if (value != mToggleFullScreen->isChecked()) { + mToggleFullScreen->activate(); + } +} + + +bool MainWindow::queryClose() { + mDocument->saveBeforeClosing(); + + KConfig* config=KGlobal::config(); + + // Don't store dock layout if only the image dock is visible. This avoid + // saving layout when in "fullscreen" or "image only" mode. + if (mFileViewController->isVisible() || mDirViewController->widget()->isVisible()) { + mDockArea->writeDockConfig(config,CONFIG_DOCK_GROUP); + } + + if (FileViewConfig::deleteCacheOnExit()) { + QString dir=ThumbnailLoadJob::thumbnailBaseDir(); + + if (QFile::exists(dir)) { + KURL url; + url.setPath(dir); + KIO::NetAccess::del(url, this); + } + } + + if (!mToggleFullScreen->isChecked()) { + saveMainWindowSettings(KGlobal::config(), "MainWindow"); + } + MiscConfig::setHistory( mURLEdit->historyItems() ); + MiscConfig::writeConfig(); + return true; +} + +void MainWindow::saveProperties( KConfig* cfg ) { + cfg->writeEntry( CONFIG_SESSION_URL, mFileViewController->url().url()); +} + +void MainWindow::readProperties( KConfig* cfg ) { + KURL url(cfg->readEntry(CONFIG_SESSION_URL)); + openURL(url); +} + +//----------------------------------------------------------------------- +// +// Public slots +// +//----------------------------------------------------------------------- +void MainWindow::openURL(const KURL& url) { + bool isDir = urlIsDirectory(this, url); + LOG("url=" << url.prettyURL() << ", isDir=" << isDir); + + if (isDir) { + mFileViewController->setDirURL(url); + mFileViewController->setFocus(); + } else { + mDocument->setURL(url); + mFileViewController->setDirURL(url.upURL()); + mFileViewController->setFileNameToSelect(url.filename()); + mImageViewController->setFocus(); + } + + if (!mToggleFullScreen->isChecked() && !isDir && !mSwitchToViewMode->isChecked()) { + mSwitchToViewMode->activate(); + } +} + +void MainWindow::slotRenamed(const QString& fileName) { + KURL url = mDocument->url(); + url.setFileName(fileName); + mDocument->setURL(url); +} + +void MainWindow::slotDirURLChanged(const KURL& dirURL) { + LOG(dirURL.prettyURL(0,KURL::StripFileProtocol)); + + mGoUp->setEnabled(dirURL.path()!="/"); + + updateStatusInfo(); + updateImageActions(); + updateLocationURL(); +} + +void MainWindow::updateLocationURL() { + LOG(""); + KURL url; + if (mSwitchToBrowseMode->isChecked()) { + url=mFileViewController->dirURL(); + if (!url.isValid()) { + url=mDocument->url(); + } + } else { + url=mDocument->url(); + } + LOG(url.prettyURL()); + mURLEdit->setEditText(url.pathOrURL()); + mURLEdit->addToHistory(url.pathOrURL()); +} + +void MainWindow::goUp() { + KURL url = mFileViewController->dirURL(); + mFileViewController->setDirURL(url.upURL()); + mFileViewController->setFileNameToSelect(url.fileName()); +} + +void MainWindow::updateFullScreenLabel() { + CaptionFormatter formatter; + formatter.mPath=mDocument->url().path(); + formatter.mFileName=mDocument->url().fileName(); + formatter.mComment=mDocument->comment(); + formatter.mImageSize=mDocument->image().size(); + formatter.mPosition=mFileViewController->shownFilePosition()+1; + formatter.mCount=mFileViewController->fileCount(); + formatter.mAperture=mDocument->aperture(); + formatter.mExposureTime=mDocument->exposureTime(); + formatter.mIso=mDocument->iso(); + formatter.mFocalLength=mDocument->focalLength(); + + QString txt=formatter.format( FullScreenConfig::osdFormat() ); + mFullScreenLabelAction->label()->setText(txt); +} + +void MainWindow::goUpTo(int id) { + KPopupMenu* menu=mGoUp->popupMenu(); + KURL url(menu->text(id)); + KURL childURL; + int index=menu->indexOf(id); + if (index>0) { + childURL=KURL(menu->text(menu->idAt(index-1))); + } else { + childURL=mDocument->dirURL(); + } + mFileViewController->setDirURL(url); + mFileViewController->setFileNameToSelect(childURL.fileName()); +} + +void MainWindow::fillGoUpMenu() { + QPopupMenu* menu = mGoUp->popupMenu(); + menu->clear(); + int pos = 0; + KURL url = mFileViewController->dirURL().upURL(); + for (; url.hasPath() && pos<10; url=url.upURL(), ++pos) { + menu->insertItem(url.pathOrURL()); + if (url.path()=="/") break; + } +} + + +//----------------------------------------------------------------------- +// +// File operations +// +//----------------------------------------------------------------------- +void MainWindow::goHome() { + KURL url; + url.setPath( QDir::homeDirPath() ); + mFileViewController->setDirURL(url); +} + + +void MainWindow::renameFile() { + KURL url; + if (mFileViewController->isVisible()) { + KURL::List list = mFileViewController->selectedURLs(); + Q_ASSERT(list.count()==1); + if (list.count()!=1) return; + url = list.first(); + } else { + url = mDocument->url(); + } + FileOperation::rename(url, this, this, SLOT(slotRenamed(const QString &))); +} + + +void MainWindow::copyFiles() { + KURL::List list; + if (mFileViewController->isVisible()) { + list = mFileViewController->selectedURLs(); + } else { + list << mDocument->url(); + } + FileOperation::copyTo(list, this); +} + +void MainWindow::linkFiles() { + KURL::List list; + if (mFileViewController->isVisible()) { + list = mFileViewController->selectedURLs(); + } else { + list << mDocument->url(); + } + FileOperation::linkTo(list, this); +} + + +void MainWindow::moveFiles() { + KURL::List list; + if (mFileViewController->isVisible()) { + list = mFileViewController->selectedURLs(); + } else { + list << mDocument->url(); + } + FileOperation::moveTo(list, this); +} + + +void MainWindow::deleteFiles() { + KURL::List list; + if (mFileViewController->isVisible()) { + list = mFileViewController->selectedURLs(); + } else { + list << mDocument->url(); + } + FileOperation::del(list, this); +} + + +void MainWindow::makeDir() { + FileOperation::makeDir(mFileViewController->dirURL(), this); +} + + +void MainWindow::showFileProperties() { + if (mFileViewController->isVisible()) { + const KFileItemList* list = mFileViewController->currentFileView()->selectedItems(); + if (list->count() > 0) { + (void)new KPropertiesDialog(*list, this); + } else { + (void)new KPropertiesDialog(mFileViewController->dirURL(), this); + } + } else { + (void)new KPropertiesDialog(mDocument->url(), this); + } +} + + +void MainWindow::rotateLeft() { + mDocument->transform(ImageUtils::ROT_270); +} + +void MainWindow::rotateRight() { + mDocument->transform(ImageUtils::ROT_90); +} + +void MainWindow::mirror() { + mDocument->transform(ImageUtils::HFLIP); +} + +void MainWindow::flip() { + mDocument->transform(ImageUtils::VFLIP); +} + +void MainWindow::showFileDialog() { + KURL url=KFileDialog::getOpenURL(); + if (!url.isValid()) return; + + openURL(url); +} + + +void MainWindow::printFile() { + KPrinter printer; + + printer.setDocName(mDocument->filename()); + const KAboutData* pAbout = KApplication::kApplication()->aboutData(); + QString nm = pAbout->appName(); + nm += "-"; + nm += pAbout->version(); + printer.setCreator( nm ); + + KPrinter::addDialogPage( new PrintDialogPage( mDocument, this, " page")); + + if (printer.setup(this, QString::null, true)) { + mDocument->print(&printer); + } +} + + +//----------------------------------------------------------------------- +// +// Private slots +// +//----------------------------------------------------------------------- +void MainWindow::openFileViewControllerContextMenu(const QPoint& pos, bool onItem) { + int selectionSize; + ExternalToolContext* externalToolContext; + + if (onItem) { + const KFileItemList* items = mFileViewController->currentFileView()->selectedItems(); + selectionSize = items->count(); + externalToolContext = + ExternalToolManager::instance()->createContext(this, items); + } else { + selectionSize = 0; + externalToolContext = + ExternalToolManager::instance()->createContext(this, mFileViewController->dirURL()); + } + + QPopupMenu menu(this); + + menu.insertItem( + i18n("External Tools"), externalToolContext->popupMenu()); + + actionCollection()->action("view_sort")->plug(&menu); + mGoUp->plug(&menu); + + menu.insertItem(SmallIcon("folder_new"), i18n("New Folder..."), this, SLOT(makeDir())); + + menu.insertSeparator(); + + if (selectionSize==1) { + mRenameFile->plug(&menu); + } + + if (selectionSize>=1) { + mCopyFiles->plug(&menu); + mMoveFiles->plug(&menu); + mLinkFiles->plug(&menu); + mDeleteFiles->plug(&menu); + menu.insertSeparator(); + } + + mShowFileProperties->plug(&menu); + menu.exec(pos); +} + + +void MainWindow::slotImageLoading() { + if (FullScreenConfig::showBusyPtr() || !mToggleFullScreen->isChecked()) { + kapp->setOverrideCursor(KCursor::workingCursor(), true /* replace */); + } +} + + +void MainWindow::slotImageLoaded() { + // Reciproc of slotImageLoading + if (FullScreenConfig::showBusyPtr() || !mToggleFullScreen->isChecked()) { + kapp->restoreOverrideCursor(); + } + updateStatusInfo(); + updateImageActions(); + updateLocationURL(); + if (mToggleFullScreen->isChecked()) { + updateFullScreenLabel(); + } +} + + +void MainWindow::hideToolBars() { + QPtrListIterator it=toolBarIterator(); + KToolBar* bar; + + for(;it.current()!=0L; ++it) { + bar=it.current(); + if (bar->area()) { + bar->area()->hide(); + } else { + bar->hide(); + } + } +} + + +void MainWindow::showToolBars() { + QPtrListIterator it=toolBarIterator(); + + KToolBar* bar; + + for(;it.current()!=0L; ++it) { + bar=it.current(); + if (bar->area()) { + bar->area()->show(); + } else { + bar->show(); + } + } +} + + +void MainWindow::toggleFullScreen() { + if (mToggleFullScreen->isChecked()) { + saveMainWindowSettings(KGlobal::config(), "MainWindow"); + + showFullScreen(); + menuBar()->hide(); + statusBar()->hide(); + + /* Hide toolbar + * If the toolbar is docked we hide the DockArea to avoid + * having a one pixel band remaining + * For the same reason, we hide all the empty DockAreas + * + * NOTE: This does not work really well if the toolbar is in + * the left or right dock area. + */ + hideToolBars(); + if (leftDock()->isEmpty()) leftDock()->hide(); + if (rightDock()->isEmpty()) rightDock()->hide(); + if (topDock()->isEmpty()) topDock()->hide(); + if (bottomDock()->isEmpty()) bottomDock()->hide(); + + if (mSwitchToBrowseMode->isChecked()) { + mImageViewController->widget()->reparent(mViewModeWidget, QPoint(0,0)); + mCentralStack->raiseWidget(StackIDView); + } + updateFullScreenLabel(); + mImageViewController->setFullScreen(true); + mImageViewController->setFocus(); + } else { + // Stop the slideshow if it's running + if (mSlideShow->isRunning()) { + mToggleSlideShow->activate(); + } + + // Make sure the file view points to the right URL, it might not be the + // case if we are getting out of a slideshow + mFileViewController->setDirURL(mDocument->url().upURL()); + mFileViewController->setFileNameToSelect(mDocument->url().fileName()); + + showNormal(); + menuBar()->show(); + + showToolBars(); + leftDock()->show(); + rightDock()->show(); + topDock()->show(); + bottomDock()->show(); + + statusBar()->show(); + mImageViewController->setFullScreen(false); + + if (mSwitchToBrowseMode->isChecked()) { + mImageDock->setWidget(mImageViewController->widget()); + mCentralStack->raiseWidget(StackIDBrowse); + mFileViewController->setFocus(); + } + } +} + + +void MainWindow::toggleSlideShow() { + if (mSlideShow->isRunning()) { + mSlideShow->stop(); + return; + } + + KURL::List list; + KFileItemListIterator it( *mFileViewController->currentFileView()->items() ); + for ( ; it.current(); ++it ) { + KFileItem* item=it.current(); + if (!item->isDir() && !Archive::fileItemIsArchive(item)) { + list.append(item->url()); + } + } + if (list.count()==0) { + return; + } + + if (SlideShowConfig::fullscreen() && !mToggleFullScreen->isChecked()) { + mToggleFullScreen->activate(); + } + mSlideShow->start(list); + } + + +void MainWindow::slotSlideShowChanged(bool running) { + mToggleSlideShow->setIcon(running ? "slideshow_pause" : "slideshow_play"); +} + + +void MainWindow::showConfigDialog() { +#ifdef GV_HAVE_KIPI + if (!mPluginLoader) loadPlugins(); + ConfigDialog dialog(this, mPluginLoader); +#else + ConfigDialog dialog(this, 0); +#endif + connect(&dialog, SIGNAL(settingsChanged()), + mSlideShow, SLOT(slotSettingsChanged()) ); + connect(&dialog, SIGNAL(settingsChanged()), + mImageViewController, SLOT(updateFromSettings()) ); + connect(&dialog, SIGNAL(settingsChanged()), + mFileViewController, SLOT(updateFromSettings()) ); + dialog.exec(); +} + + +void MainWindow::showExternalToolDialog() { + ExternalToolDialog* dialog=new ExternalToolDialog(this); + dialog->show(); +} + + +void MainWindow::showKeyDialog() { + KKeyDialog dialog(true, this); + dialog.insert(actionCollection()); + dialog.configure(true); +} + + +void MainWindow::showToolBarDialog() { + saveMainWindowSettings(KGlobal::config(), "MainWindow"); + KEditToolbar dlg(actionCollection()); + connect(&dlg,SIGNAL(newToolbarConfig()),this,SLOT(applyMainWindowSettings())); + dlg.exec(); +} + +void MainWindow::applyMainWindowSettings() { + createGUI(); + KMainWindow::applyMainWindowSettings(KGlobal::config(), "MainWindow"); +} + + + +void MainWindow::escapePressed() { + if (mToggleFullScreen->isChecked()) { + mToggleFullScreen->activate(); + } +} + + +void MainWindow::slotDirRenamed(const KURL& oldURL, const KURL& newURL) { + LOG(oldURL.prettyURL(0,KURL::StripFileProtocol) << " to " << newURL.prettyURL(0,KURL::StripFileProtocol)); + + KURL url(mFileViewController->dirURL()); + if (!oldURL.isParentOf(url) ) { + LOG(oldURL.prettyURL() << " is not a parent of " << url.prettyURL()); + return; + } + + QString oldPath=oldURL.path(); + LOG("current path: " << url.path() ); + QString path=newURL.path() + url.path().mid(oldPath.length()); + LOG("new path: " << path); + url.setPath(path); + mFileViewController->setDirURL(url); +} + + +void MainWindow::slotGo() { + KURL url(mURLEditCompletion->replacedPath(mURLEdit->currentText())); + LOG(url.prettyURL()); + openURL(url); + mFileViewController->setFocus(); +} + +void MainWindow::slotShownFileItemRefreshed(const KFileItem*) { + LOG(""); + mDocument->reload(); +} + + +void MainWindow::slotToggleCentralStack() { + LOG(""); + if (mSwitchToBrowseMode->isChecked()) { + mImageDock->setWidget(mImageViewController->widget()); + mCentralStack->raiseWidget(StackIDBrowse); + mFileViewController->setSilentMode( false ); + // force re-reading the directory to show the error + if( mFileViewController->lastURLError()) mFileViewController->retryURL(); + } else { + mImageViewController->widget()->reparent(mViewModeWidget, QPoint(0,0)); + mCentralStack->raiseWidget(StackIDView); + mFileViewController->setSilentMode( true ); + } + + // Make sure the window list actions are disabled if we are in view mode, + // otherwise weird things happens when we go back to browse mode + QPtrListIterator it(mWindowListActions); + for (;it.current(); ++it) { + it.current()->setEnabled(mSwitchToBrowseMode->isChecked()); + } + updateImageActions(); + updateLocationURL(); +} + + +void MainWindow::resetDockWidgets() { + int answer=KMessageBox::warningContinueCancel(this, + i18n("You are about to revert the window setup to factory defaults, are you sure?"), + QString::null /* caption */, + i18n("Reset")); + if (answer==KMessageBox::Cancel) return; + + mFolderDock->undock(); + mImageDock->undock(); + mMetaDock->undock(); + + mFolderDock->manualDock(mFileDock, KDockWidget::DockLeft, 4000); + mImageDock->manualDock(mFolderDock, KDockWidget::DockBottom, 3734); + mMetaDock->manualDock(mImageDock, KDockWidget::DockBottom, 8560); +} + + +/** + * Display a hint as a temporary message in the status bar + */ +void MainWindow::showHint(const QString& hint) { + mSBHintLabel->setText(hint); + + mSBHintLabel->show(); + mHintTimer->start(HINT_TIMEOUT, true); +} + + +//----------------------------------------------------------------------- +// +// GUI +// +//----------------------------------------------------------------------- +void MainWindow::updateStatusInfo() { + QStringList tokens; + + if ( KProtocolInfo::supportsListing(mFileViewController->url()) ) { + int pos = mFileViewController->shownFilePosition(); + uint count = mFileViewController->fileCount(); + if (count > 0) { + tokens << i18n("%1/%2").arg(pos+1).arg(count); + } else { + tokens << i18n("No images"); + } + } + + QString filename = mDocument->filename(); + + QSize size = mDocument->image().size(); + if (!size.isEmpty()) { + tokens << i18n("%1 x %2 pixels").arg(size.width()).arg(size.height()); + } + + mSBDetailLabel->setText(tokens.join(" - ")); + setCaption(filename); +} + + +void MainWindow::updateImageActions() { + mToggleSlideShow->setEnabled(mDocument->urlKind()!=MimeTypeUtils::KIND_UNKNOWN); + + bool imageActionsEnabled = !mDocument->isNull(); + + mRotateLeft->setEnabled(imageActionsEnabled); + mRotateRight->setEnabled(imageActionsEnabled); + mMirror->setEnabled(imageActionsEnabled); + mFlip->setEnabled(imageActionsEnabled); + mSaveFile->setEnabled(imageActionsEnabled); + mSaveFileAs->setEnabled(imageActionsEnabled); + mFilePrint->setEnabled(imageActionsEnabled); + mReload->setEnabled(imageActionsEnabled); + + bool fileActionsEnabled = + imageActionsEnabled + || (mFileViewController->isVisible() && mFileViewController->selectionSize()>0); + + mRenameFile->setEnabled(fileActionsEnabled); + mCopyFiles->setEnabled(fileActionsEnabled); + mMoveFiles->setEnabled(fileActionsEnabled); + mLinkFiles->setEnabled(fileActionsEnabled); + mDeleteFiles->setEnabled(fileActionsEnabled); + mShowFileProperties->setEnabled(fileActionsEnabled); +} + + +/** + * This method creates all the widgets. Interactions between them and with + * actions are created in createObjectInteractions + */ +void MainWindow::createWidgets() { + KConfig* config=KGlobal::config(); + + mCentralStack=new QWidgetStack(this); + setCentralWidget(mCentralStack); + + mDockArea=new KDockArea(mCentralStack); + mCentralStack->addWidget(mDockArea, StackIDBrowse); + mDockArea->manager()->setSplitterHighResolution(true); + mDockArea->manager()->setSplitterOpaqueResize(true); + + mViewModeWidget=new QWidget(mCentralStack); + QVBoxLayout* layout=new QVBoxLayout(mViewModeWidget); + layout->setAutoAdd(true); + mCentralStack->addWidget(mViewModeWidget); + + // Status bar + mSBDetailLabel=new QLabel("", statusBar()); + + mSBHintLabel=new TruncatedTextLabel(statusBar()); + QFont font=mSBHintLabel->font(); + font.setItalic(true); + mSBHintLabel->setFont(font); + + statusBar()->addWidget(mSBDetailLabel, 0); + statusBar()->addWidget(mSBHintLabel, 1); + mHintTimer=new QTimer(this); + connect(mHintTimer, SIGNAL(timeout()), + mSBHintLabel, SLOT(clear()) ); + + // Pixmap widget + mImageDock = mDockArea->createDockWidget("Image",SmallIcon("gwenview"),NULL,i18n("Image")); + mImageViewController=new ImageViewController(mImageDock, mDocument, actionCollection()); + mImageDock->setWidget(mImageViewController->widget()); + connect(mImageViewController, SIGNAL(requestHintDisplay(const QString&)), + this, SLOT(showHint(const QString&)) ); + + // Folder widget + mFolderDock = mDockArea->createDockWidget("Folders",SmallIcon("folder_open"),NULL,i18n("Folders")); + VTabWidget* vtabWidget=new VTabWidget(mFolderDock); + mFolderDock->setWidget(vtabWidget); + + mDirViewController=new DirViewController(vtabWidget); + vtabWidget->addTab(mDirViewController->widget(), SmallIcon("folder"), i18n("Folders")); + + mBookmarkViewController=new BookmarkViewController(vtabWidget); + vtabWidget->addTab(mBookmarkViewController->widget(), SmallIcon("bookmark"), i18n("Bookmarks")); + + // File widget + mFileDock = mDockArea->createDockWidget("Files",SmallIcon("image"),NULL,i18n("Files")); + mFileViewController=new FileViewController(this, actionCollection()); + mFileDock->setWidget(mFileViewController); + mFileDock->setEnableDocking(KDockWidget::DockNone); + mDockArea->setMainDockWidget(mFileDock); + + // Meta info edit widget + mMetaDock = mDockArea->createDockWidget("File Attributes", SmallIcon("info"),NULL, + i18n("Image Comment")); + mMetaEdit = new MetaEdit(mMetaDock, mDocument); + mMetaDock->setWidget(mMetaEdit); + + // Slide show controller (not really a widget) + mSlideShow=new SlideShow(mDocument); + + // Default position on desktop + setGeometry(20,20,720,520); + + // Default dock config + // (The "magic numbers" were found by adjusting the layout from within the + // app and looking at the result in the configuration file) + mFolderDock->manualDock(mFileDock, KDockWidget::DockLeft, 4000); + mImageDock->manualDock(mFolderDock, KDockWidget::DockBottom, 3734); + mMetaDock->manualDock(mImageDock, KDockWidget::DockBottom, 8560); + + // Load dock config if up to date + if (config->hasGroup(CONFIG_DOCK_GROUP)) { + config->setGroup(CONFIG_DOCK_GROUP); + if (config->readNumEntry(CONFIG_GWENVIEW_DOCK_VERSION, 1)==GWENVIEW_DOCK_VERSION) { + mDockArea->readDockConfig(config,CONFIG_DOCK_GROUP); + } else { + KMessageBox::sorry(this, i18n( + "Configuration update
" + "Due to some changes in the dock behavior, your old dock configuration has been discarded. " + "Please adjust your docks again.
") + ); + // Store the default dock config and create the + // GWENVIEW_DOCK_VERSION entry + mDockArea->writeDockConfig(config,CONFIG_DOCK_GROUP); + config->writeEntry(CONFIG_GWENVIEW_DOCK_VERSION, GWENVIEW_DOCK_VERSION); + config->sync(); + } + } else { + // There was no dock config, lets create the GWENVIEW_DOCK_VERSION entry + config->setGroup(CONFIG_DOCK_GROUP); + config->writeEntry(CONFIG_GWENVIEW_DOCK_VERSION, GWENVIEW_DOCK_VERSION); + config->sync(); + } + + // Load config + Cache::instance()->readConfig(config,CONFIG_CACHE_GROUP); +} + + +/** + * This method creates all the actions Interactions between them and with + * widgets are created in createObjectInteractions + */ +void MainWindow::createActions() { + // Stack + mSwitchToBrowseMode=new KRadioAction(i18n("Browse"), "folder_image", CTRL + Key_Return, this, SLOT(slotToggleCentralStack()), actionCollection(), "switch_to_browse_mode"); + mSwitchToBrowseMode->setExclusiveGroup("centralStackMode"); + mSwitchToBrowseMode->setChecked(true); + mSwitchToViewMode=new KRadioAction(i18n("View Image"), "image", 0, this, SLOT(slotToggleCentralStack()), actionCollection(), "switch_to_view_mode"); + mSwitchToViewMode->setExclusiveGroup("centralStackMode"); + + // File + KStdAction::open(this,SLOT(showFileDialog()),actionCollection() ); + mSaveFile=KStdAction::save(mDocument,SLOT(save()),actionCollection() ); + mSaveFileAs=KStdAction::saveAs(mDocument,SLOT(saveAs()),actionCollection() ); + mFilePrint = KStdAction::print(this, SLOT(printFile()), actionCollection()); + mRenameFile=new KAction(i18n("&Rename..."),Key_F2,this,SLOT(renameFile()),actionCollection(),"file_rename"); + mCopyFiles=new KAction(i18n("&Copy To..."),Key_F7,this,SLOT(copyFiles()),actionCollection(),"file_copy"); + mMoveFiles=new KAction(i18n("&Move To..."),Key_F8,this,SLOT(moveFiles()),actionCollection(),"file_move"); + mLinkFiles=new KAction(i18n("&Link To..."),Key_F9,this,SLOT(linkFiles()),actionCollection(),"file_link"); + mDeleteFiles=new KAction(i18n("&Delete"),"editdelete",Key_Delete,this,SLOT(deleteFiles()),actionCollection(),"file_delete"); + mShowFileProperties=new KAction(i18n("Properties"),0,this,SLOT(showFileProperties()),actionCollection(),"file_properties"); + KStdAction::quit( kapp, SLOT (closeAllWindows()), actionCollection() ); + + // Edit + mRotateLeft=new KAction(i18n("Rotate &Left"),"rotate_left",CTRL + Key_L, this, SLOT(rotateLeft()),actionCollection(),"rotate_left"); + mRotateRight=new KAction(i18n("Rotate &Right"),"rotate_right",CTRL + Key_R, this, SLOT(rotateRight()),actionCollection(),"rotate_right"); + mMirror=new KAction(i18n("&Mirror"),"mirror",0, this, SLOT(mirror()),actionCollection(),"mirror"); + mFlip=new KAction(i18n("&Flip"),"flip",0, this, SLOT(flip()),actionCollection(),"flip"); + + // View + mReload=new KAction(i18n("Reload"), "reload", Key_F5, mDocument, SLOT(reload()), actionCollection(), "reload"); + mReload->setEnabled(false); + + mToggleFullScreen= KStdAction::fullScreen(this,SLOT(toggleFullScreen()),actionCollection(),0); + mToggleSlideShow=new KAction(i18n("Slide Show"),"slideshow_play",0,this,SLOT(toggleSlideShow()),actionCollection(),"slideshow"); + mFullScreenLabelAction=new KToolBarLabelAction("", 0, 0, 0, actionCollection(), "fullscreen_label"); + + // Go + mGoUp=new KToolBarPopupAction(i18n("Up"), "up", ALT + Key_Up, this, SLOT(goUp()), actionCollection(), "go_up"); + new KAction( i18n( "Home" ), "gohome", KStdAccel::shortcut(KStdAccel::Home), this, SLOT(goHome()), actionCollection(), "go_home"); + + // Window + mResetDockWidgets = new KAction(i18n("Reset"), 0, this, SLOT(resetDockWidgets()), actionCollection(), "reset_dock_widgets"); + + // Settings + mShowConfigDialog= + KStdAction::preferences(this, SLOT(showConfigDialog()), actionCollection() ); + mShowKeyDialog= + KStdAction::keyBindings(this, SLOT(showKeyDialog()), actionCollection() ); + (void)new KAction(i18n("Configure External Tools..."), "configure", 0, + this, SLOT(showExternalToolDialog()), actionCollection(), "configure_tools"); + (void)KStdAction::configureToolbars( + this, SLOT(showToolBarDialog()), actionCollection() ); + + actionCollection()->readShortcutSettings(); +} + + +/** + * This method creates the interactions between objects, when it's called, all + * widgets and actions have already been created + */ +void MainWindow::createObjectInteractions() { + // Actions in image view + { + KActionPtrList actions; + actions + << mToggleFullScreen + << mToggleSlideShow + << mFileViewController->selectPrevious() + << mFileViewController->selectNext() + << mRotateLeft + << mRotateRight + << mFullScreenLabelAction + ; + mImageViewController->setFullScreenCommonActions(actions); + } + + { + KActionPtrList actions; + actions + << mFileViewController->selectPrevious() + << mFileViewController->selectNext() + << mReload + ; + mImageViewController->setNormalCommonActions(actions); + } + + { + KActionPtrList actions; + actions + << actionCollection()->action("view_zoom_in") + << actionCollection()->action("view_zoom_to") + << actionCollection()->action("view_zoom_out") + << mRotateLeft + << mRotateRight + ; + mImageViewController->setImageViewActions(actions); + } + + // Make sure file actions are correctly updated + connect(mFileViewController, SIGNAL(selectionChanged()), + this, SLOT(updateImageActions()) ); + + connect(mFileViewController, SIGNAL(requestContextMenu(const QPoint&, bool)), + this, SLOT(openFileViewControllerContextMenu(const QPoint&, bool)) ); + + // Bookmarks + QString file = locate( "data", "kfile/bookmarks.xml" ); + if (file.isEmpty()) { + file = locateLocal( "data", "kfile/bookmarks.xml" ); + } + + KBookmarkManager* manager=KBookmarkManager::managerForFile(file,false); + manager->setUpdate(true); + manager->setShowNSBookmarks(false); + mBookmarkViewController->init(manager); + + BookmarkOwner* bookmarkOwner=new BookmarkOwner(this); + + KActionMenu* bookmark=new KActionMenu(i18n( "&Bookmarks" ), "bookmark", actionCollection(), "bookmarks" ); + new KBookmarkMenu(manager, bookmarkOwner, bookmark->popupMenu(), 0, true); + + connect(bookmarkOwner,SIGNAL(openURL(const KURL&)), + mFileViewController,SLOT(setDirURL(const KURL&)) ); + + connect(mFileViewController,SIGNAL(directoryChanged(const KURL&)), + bookmarkOwner,SLOT(setURL(const KURL&)) ); +} + + +void MainWindow::createHideShowAction(KDockWidget* dock) { + QString caption; + if (dock->mayBeHide()) { + caption=i18n("Hide %1").arg(dock->caption()); + } else { + caption=i18n("Show %1").arg(dock->caption()); + } + + KAction* action=new KAction(caption, 0, dock, SLOT(changeHideShowState()), (QObject*)0 ); + if (dock->icon()) { + action->setIconSet( QIconSet(*dock->icon()) ); + } + mWindowListActions.append(action); +} + + +void MainWindow::updateWindowActions() { + unplugActionList("winlist"); + mWindowListActions.clear(); + createHideShowAction(mFolderDock); + createHideShowAction(mImageDock); + createHideShowAction(mMetaDock); + plugActionList("winlist", mWindowListActions); +} + + +void MainWindow::createConnections() { + connect(mGoUp->popupMenu(), SIGNAL(aboutToShow()), + this,SLOT(fillGoUpMenu())); + + connect(mGoUp->popupMenu(), SIGNAL(activated(int)), + this,SLOT(goUpTo(int))); + + // Slideshow connections + connect( mSlideShow, SIGNAL(nextURL(const KURL&)), + SLOT( openURL(const KURL&)) ); + connect( mSlideShow, SIGNAL( stateChanged(bool)), + SLOT( slotSlideShowChanged(bool)) ); + + // Dir view connections + connect(mDirViewController, SIGNAL(urlChanged(const KURL&)), + mFileViewController, SLOT(setDirURL(const KURL&)) ); + connect(mDirViewController, SIGNAL(urlRenamed(const KURL&, const KURL&)), + this, SLOT(slotDirRenamed(const KURL&, const KURL&)) ); + + // Bookmark view connections + connect(mBookmarkViewController, SIGNAL(openURL(const KURL&)), + mFileViewController,SLOT(setDirURL(const KURL&)) ); + connect(mFileViewController, SIGNAL(directoryChanged(const KURL&)), + mBookmarkViewController, SLOT(setURL(const KURL&)) ); + + // Pixmap view connections + connect(mImageViewController, SIGNAL(selectPrevious()), + mFileViewController, SLOT(slotSelectPrevious()) ); + connect(mImageViewController, SIGNAL(selectNext()), + mFileViewController, SLOT(slotSelectNext()) ); + connect(mImageViewController, SIGNAL(doubleClicked()), + mToggleFullScreen, SLOT(activate()) ); + + // File view connections + connect(mFileViewController,SIGNAL(urlChanged(const KURL&)), + mDocument,SLOT(setURL(const KURL&)) ); + connect(mFileViewController,SIGNAL(directoryChanged(const KURL&)), + this,SLOT(slotDirURLChanged(const KURL&)) ); + connect(mFileViewController,SIGNAL(directoryChanged(const KURL&)), + mDirViewController,SLOT(setURL(const KURL&)) ); + connect(mFileViewController,SIGNAL(directoryChanged(const KURL&)), + mHistory,SLOT(addURLToHistory(const KURL&)) ); + + connect(mFileViewController,SIGNAL(completed()), + this,SLOT(updateStatusInfo()) ); + connect(mFileViewController,SIGNAL(canceled()), + this,SLOT(updateStatusInfo()) ); + connect(mFileViewController,SIGNAL(imageDoubleClicked()), + mToggleFullScreen,SLOT(activate()) ); + connect(mFileViewController,SIGNAL(shownFileItemRefreshed(const KFileItem*)), + this,SLOT(slotShownFileItemRefreshed(const KFileItem*)) ); + connect(mFileViewController,SIGNAL(sortingChanged()), + this, SLOT(updateStatusInfo()) ); + + // History connections + connect(mHistory, SIGNAL(urlChanged(const KURL&)), + mFileViewController, SLOT(setDirURL(const KURL&)) ); + + // Document connections + connect(mDocument,SIGNAL(loading()), + this,SLOT(slotImageLoading()) ); + connect(mDocument,SIGNAL(loaded(const KURL&)), + this,SLOT(slotImageLoaded()) ); + connect(mDocument,SIGNAL(saved(const KURL&)), + mFileViewController,SLOT(updateThumbnail(const KURL&)) ); + connect(mDocument,SIGNAL(reloaded(const KURL&)), + mFileViewController,SLOT(updateThumbnail(const KURL&)) ); + + // Location bar + connect(mURLEdit, SIGNAL(activated(const QString &)), + this,SLOT(slotGo()) ); + connect(mURLEdit, SIGNAL(returnPressed()), + this,SLOT(slotGo()) ); + + // Non configurable stop-fullscreen accel + QAccel* accel=new QAccel(this); + accel->connectItem(accel->insertItem(Key_Escape),this,SLOT(escapePressed())); + + // Dock related + connect(mDockArea->manager(), SIGNAL(change()), + this, SLOT(updateWindowActions()) ); + + // Plugin menu + QPopupMenu *popup = static_cast( + factory()->container( "plugins", this)); + connect(popup, SIGNAL(aboutToShow()), this, SLOT(loadPlugins()) ); +} + + +void MainWindow::createLocationToolBar() { + // URL Combo + mURLEdit=new KHistoryCombo(); + mURLEdit->setDuplicatesEnabled(false); + mURLEdit->setPixmapProvider(new KURLPixmapProvider); + mURLEdit->setMaxCount(HISTORY_MAX_COUNT); + mURLEdit->setHistoryItems(MiscConfig::history()); + + // Do not let the combobox get wider than available space, as this would + // hide the toolbuttons after it + mURLEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + // Avoid stealing focus + mURLEdit->setFocusPolicy(ClickFocus); + + mURLEditCompletion=new KURLCompletion(); + + mURLEdit->setCompletionObject(mURLEditCompletion); + mURLEdit->setAutoDeleteCompletionObject(true); + + KWidgetAction* comboAction=new KWidgetAction( mURLEdit, i18n("Location Bar"), 0, + 0, 0, actionCollection(), "location_url"); + comboAction->setShortcutConfigurable(false); + comboAction->setAutoSized(true); + + // Clear button + (void)new KAction( i18n("Clear Location Bar"), + QApplication::reverseLayout()?"clear_left" : "locationbar_erase", + 0, this, SLOT(clearLocationLabel()), actionCollection(), "clear_location"); + + // URL Label + KToolBarLabelAction* locationAction = new KToolBarLabelAction(i18n("L&ocation:"), + Key_F6, this, SLOT( activateLocationLabel()), actionCollection(), "location_label"); + locationAction->setBuddy(mURLEdit); + + // Go button + (void)new KAction(i18n("Go"), "key_enter", 0, this, SLOT(slotGo()), actionCollection(), "location_go"); + +} + + +void MainWindow::clearLocationLabel() { + mURLEdit->clearEdit(); + mURLEdit->setFocus(); +} + + +void MainWindow::activateLocationLabel() { + mURLEdit->setFocus(); + mURLEdit->lineEdit()->selectAll(); +} + + +#ifdef GV_HAVE_KIPI +void MainWindow::loadPlugins() { + // Already done + if (mPluginLoader) return; + + LOG("Load plugins"); + // Sets up the plugin interface, and load the plugins + KIPIInterface* interface = new KIPIInterface(this, mFileViewController); + mPluginLoader = new KIPI::PluginLoader(QStringList(), interface ); + connect( mPluginLoader, SIGNAL( replug() ), this, SLOT( slotReplug() ) ); + mPluginLoader->loadPlugins(); +} + + +// Helper class for slotReplug(), gcc does not want to instantiate templates +// with local classes, so this is declared outside of slotReplug() +struct MenuInfo { + QString mName; + QPtrList mActions; + MenuInfo() {} + MenuInfo(const QString& name) : mName(name) {} +}; + +void MainWindow::slotReplug() { + typedef QMap CategoryMap; + CategoryMap categoryMap; + categoryMap[KIPI::IMAGESPLUGIN]=MenuInfo("image_actions"); + categoryMap[KIPI::EFFECTSPLUGIN]=MenuInfo("effect_actions"); + categoryMap[KIPI::TOOLSPLUGIN]=MenuInfo("tool_actions"); + categoryMap[KIPI::IMPORTPLUGIN]=MenuInfo("import_actions"); + categoryMap[KIPI::EXPORTPLUGIN]=MenuInfo("export_actions"); + categoryMap[KIPI::BATCHPLUGIN]=MenuInfo("batch_actions"); + categoryMap[KIPI::COLLECTIONSPLUGIN]=MenuInfo("collection_actions"); + + // Fill the mActions + KIPI::PluginLoader::PluginList pluginList=mPluginLoader->pluginList(); + KIPI::PluginLoader::PluginList::ConstIterator it(pluginList.begin()); + KIPI::PluginLoader::PluginList::ConstIterator itEnd(pluginList.end()); + for( ; it!=itEnd; ++it ) { + if (!(*it)->shouldLoad()) continue; + KIPI::Plugin* plugin = (*it)->plugin(); + Q_ASSERT(plugin); + if (!plugin) continue; + + plugin->setup(this); + KActionPtrList actions = plugin->actions(); + KActionPtrList::ConstIterator actionIt=actions.begin(), end=actions.end(); + for (; actionIt!=end; ++actionIt) { + KIPI::Category category = plugin->category(*actionIt); + + if (!categoryMap.contains(category)) { + kdWarning() << "Unknown category '" << category << "'\n"; + continue; + } + + categoryMap[category].mActions.append(*actionIt); + } + plugin->actionCollection()->readShortcutSettings(); + } + + // Create a dummy "no plugin" action list + KAction* noPlugin=new KAction(i18n("No Plugin"), 0, 0, 0, actionCollection(), "no_plugin"); + noPlugin->setShortcutConfigurable(false); + noPlugin->setEnabled(false); + QPtrList noPluginList; + noPluginList.append(noPlugin); + + // Fill the menu + CategoryMap::ConstIterator catIt=categoryMap.begin(), catItEnd=categoryMap.end(); + for (; catIt!=catItEnd; ++catIt) { + const MenuInfo& info=catIt.data(); + unplugActionList(info.mName); + if (info.mActions.count()>0) { + plugActionList(info.mName, info.mActions); + } else { + plugActionList(info.mName, noPluginList); + } + } +} +#else +void MainWindow::loadPlugins() { + // Create a dummy "no KIPI" action list + KAction* noPlugin=new KAction(i18n("No KIPI support"), 0, 0, 0, actionCollection(), "no_plugin"); + noPlugin->setShortcutConfigurable(false); + noPlugin->setEnabled(false); + QPtrList noPluginList; + noPluginList.append(noPlugin); + + QStringList lst; + lst << "image_actions" + << "effect_actions" + << "tool_actions" + << "import_actions" + << "export_actions" + << "batch_actions" + << "collection_actions"; + + // Fill the menu + QStringList::ConstIterator catIt=lst.begin(), catItEnd=lst.end(); + for (; catIt!=catItEnd; ++catIt) { + plugActionList(*catIt, noPluginList); + } +} + +void MainWindow::slotReplug() { +} +#endif + + +} // namespace diff --git a/src/app/mainwindow.h b/src/app/mainwindow.h new file mode 100644 index 0000000..a61d8ea --- /dev/null +++ b/src/app/mainwindow.h @@ -0,0 +1,222 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +// kate: indent-mode csands; indent-width 4; replace-tabs-save off; replace-tabs off; replace-trailing-space-save off; space-indent off; tabs-indents on; tab-width 4; +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +// Qt +#include + +// KDE +#include +#include + +// Local +#include "config.h" +#ifdef GV_HAVE_KIPI +#include +#endif + +class QLabel; +class QTimer; +class QWidgetStack; + +class KAction; +class KDockArea; +class KDockWidget; +class KFileItem; +class KHistoryCombo; +class KListView; +class KRadioAction; +class KToggleAction; +class KToolBarLabelAction; +class KToolBarPopupAction; +class KURLCompletion; + +namespace Gwenview { +class BookmarkViewController; +class DirViewController; +class Document; +class FileViewController; +class History; +class MetaEdit; +class ImageViewController; +class SlideShow; + + +class MainWindow : public KMainWindow { +Q_OBJECT +public: + MainWindow(); + void setFullScreen(bool); + FileViewController* fileViewController() const { return mFileViewController; } + +public slots: + void openURL(const KURL&); + +protected: + bool queryClose(); + virtual void saveProperties( KConfig* ); + virtual void readProperties( KConfig* ); + +private: + QWidgetStack* mCentralStack; + QWidget* mViewModeWidget; + KDockArea* mDockArea; + KDockWidget* mFolderDock; + KDockWidget* mFileDock; + KDockWidget* mImageDock; + KDockWidget* mMetaDock; + QLabel* mSBDetailLabel; + QLabel* mSBHintLabel; + QTimer* mHintTimer; + + FileViewController* mFileViewController; + DirViewController* mDirViewController; + BookmarkViewController* mBookmarkViewController; + ImageViewController* mImageViewController; + MetaEdit *mMetaEdit; + + Document* mDocument; + History* mHistory; + SlideShow* mSlideShow; + + KRadioAction* mSwitchToBrowseMode; + KRadioAction* mSwitchToViewMode; + KToggleAction* mToggleFullScreen; + KToolBarLabelAction* mFullScreenLabelAction; + KAction* mRenameFile; + KAction* mCopyFiles; + KAction* mMoveFiles; + KAction* mLinkFiles; + KAction* mDeleteFiles; + KAction* mShowConfigDialog; + KAction* mShowKeyDialog; + KAction* mReload; + KToolBarPopupAction* mGoUp; + KAction* mShowFileProperties; + KAction* mToggleSlideShow; + KAction* mRotateLeft; + KAction* mRotateRight; + KAction* mMirror; + KAction* mFlip; + KAction* mSaveFile; + KAction* mSaveFileAs; + KAction* mFilePrint; + KAction* mResetDockWidgets; + + KHistoryCombo* mURLEdit; + KURLCompletion* mURLEditCompletion; + QPtrList mWindowListActions; + +#ifdef GV_HAVE_KIPI + KIPI::PluginLoader* mPluginLoader; +#endif + + void hideToolBars(); + void showToolBars(); + void createWidgets(); + void createActions(); + void createLocationToolBar(); + void createObjectInteractions(); + void updateLocationURL(); + void updateFullScreenLabel(); + void createConnections(); + +private slots: + void goUp(); + void goUpTo(int); + + void makeDir(); + void goHome(); + void renameFile(); + void slotRenamed(const QString&); + void copyFiles(); + void moveFiles(); + void linkFiles(); + void deleteFiles(); + void showFileProperties(); + void showFileDialog(); + void printFile(); /** print the actual file */ + void clearLocationLabel(); + void activateLocationLabel(); + + void toggleFullScreen(); + void showConfigDialog(); + void showExternalToolDialog(); + void showKeyDialog(); + void showToolBarDialog(); + void applyMainWindowSettings(); + void slotImageLoading(); + void slotImageLoaded(); + void toggleSlideShow(); + void slotSlideShowChanged(bool); + void slotDirRenamed(const KURL& oldURL, const KURL& newURL); + void slotDirURLChanged(const KURL&); + void rotateLeft(); + void rotateRight(); + void mirror(); + void flip(); + void resetDockWidgets(); + + void slotToggleCentralStack(); + /** + * Update status bar and caption + */ + void updateStatusInfo(); + + /** + * Enable or disable image actions + */ + void updateImageActions(); + + void slotShownFileItemRefreshed(const KFileItem* item); + + /** + * Allow quitting full screen mode by pressing Escape key. + */ + void escapePressed(); + + /** + * Address bar related + */ + void slotGo(); + + void updateWindowActions(); + + void loadPlugins(); + + // Helper function for updateWindowActions() + void createHideShowAction(KDockWidget* dock); + + void slotReplug(); + + void showHint(const QString&); + + void fillGoUpMenu(); + + void openFileViewControllerContextMenu(const QPoint& pos, bool onItem); +}; + + +} // namespace +#endif + diff --git a/src/app/metaedit.cpp b/src/app/metaedit.cpp new file mode 100644 index 0000000..0d56f48 --- /dev/null +++ b/src/app/metaedit.cpp @@ -0,0 +1,138 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Copyright (c) 2003 Jos van den Oever + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Qt +#include +#include +#include + +// KDE +#include +#include + +// Local +#include "gvcore/document.h" +#include "metaedit.moc" +namespace Gwenview { + +// FIXME: Why doesn't MetaEdit inherits from QTextEdit rather than QVBox? +MetaEdit::MetaEdit(QWidget *parent, Document *gvp, const char *name) +: QVBox(parent, name) +, mEmpty(true) +, mDocument(gvp) +{ + mCommentEdit=new QTextEdit(this); + mCommentEdit->installEventFilter(this); + connect(mCommentEdit, SIGNAL(modificationChanged(bool)), + this, SLOT(setModified(bool))); + connect(mDocument,SIGNAL(loaded(const KURL&)), + this,SLOT(updateContent()) ); + connect(mCommentEdit, SIGNAL(textChanged()), + this, SLOT(updateDoc()) ); + updateContent(); + mCommentEdit->setMinimumHeight(int (mCommentEdit->fontMetrics().height() * 1.5) ); +} + + +MetaEdit::~MetaEdit() { +} + + +bool MetaEdit::eventFilter(QObject*, QEvent *event) { + if (mEmpty + && (mDocument->commentState()==Document::WRITABLE) + && (event->type()==QEvent::FocusIn || event->type()==QEvent::FocusOut) + ) { + setEmptyText(); + } + return false; +} + + +void MetaEdit::setModified(bool m) { + if (m && mEmpty) { + mEmpty = false; + } +} + + +void MetaEdit::updateContent() { + if (mDocument->isNull()) { + setMessage(i18n("No image selected.")); + return; + } + + if (mDocument->commentState() == Document::NONE) { + setMessage(i18n("This image cannot be commented.")); + return; + } + + QString comment=mDocument->comment(); + mEmpty = comment.isEmpty(); + if (mEmpty) { + setEmptyText(); + return; + } + setComment(comment); +} + + +void MetaEdit::updateDoc() { + if ((mDocument->commentState()==Document::WRITABLE) && mCommentEdit->isModified()) { + mDocument->setComment(mCommentEdit->text()); + mCommentEdit->setModified(false); + } +} + + +void MetaEdit::setEmptyText() { + Q_ASSERT(mDocument->commentState()!=Document::NONE); + if (mDocument->commentState()==Document::WRITABLE) { + if (mCommentEdit->hasFocus()) { + setComment(""); + } else { + setMessage(i18n("Type here to add a comment to this image.")); + } + } else { + setMessage(i18n("No comment available.")); + } +} + + +/** + * Use mCommentEdit to show the comment and let the user edit it + */ +void MetaEdit::setComment(const QString& comment) { + Q_ASSERT(mDocument->commentState()!=Document::NONE); + mCommentEdit->setTextFormat(QTextEdit::PlainText); + mCommentEdit->setReadOnly(mDocument->commentState()==Document::READ_ONLY); + mCommentEdit->setText(comment); +} + + +/** + * Use mCommentEdit to display a read-only message + */ +void MetaEdit::setMessage(const QString& msg) { + mCommentEdit->setTextFormat(QTextEdit::RichText); + mCommentEdit->setReadOnly(true); + mCommentEdit->setText(QString("%1").arg(msg)); +} + +} // namespace diff --git a/src/app/metaedit.h b/src/app/metaedit.h new file mode 100644 index 0000000..c867eba --- /dev/null +++ b/src/app/metaedit.h @@ -0,0 +1,59 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Copyright (c) 2003 Jos van den Oever + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef METAEDIT_H +#define METAEDIT_H + +// Qt +#include + +// KDE +#include +class QTextEdit; + +namespace Gwenview { + +class Document; + +class MetaEdit : public QVBox { +Q_OBJECT +public: + MetaEdit(QWidget *parent, Document*, const char *name=""); + ~MetaEdit(); +protected: + bool eventFilter(QObject *, QEvent *); +private slots: + void updateContent(); + void updateDoc(); + void setModified(bool); + +private: + bool mEmpty; + Document* mDocument; + QTextEdit* mCommentEdit; + + void setComment(const QString&); + void setMessage(const QString&); + void setEmptyText(); +}; + + +} // namespace +#endif + diff --git a/src/app/testvtabwidget.cpp b/src/app/testvtabwidget.cpp new file mode 100644 index 0000000..1e5d835 --- /dev/null +++ b/src/app/testvtabwidget.cpp @@ -0,0 +1,48 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +// kate: indent-mode csands; indent-width 4; replace-tabs-save off; replace-tabs off; replace-trailing-space-save off; space-indent off; tabs-indents on; tab-width 4; +/* +Gwenview - A simple image viewer for KDE +Copyright 2005 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Qt +#include + +// KDE +#include +#include +#include +#include + +// Local +#include + +int main(int argc, char* argv[]) { + KAboutData aboutData("testvtabwidget", "testvtabwidget", "0"); + KCmdLineArgs::init( argc, argv, &aboutData ); + KApplication app; + + Gwenview::VTabWidget tabWidget(0); + QLabel* lbl=new QLabel("label 1", &tabWidget); + tabWidget.addTab(lbl, SmallIcon("text"), "tab1"); + lbl=new QLabel("label 2", &tabWidget); + tabWidget.addTab(lbl, SmallIcon("image"), "tab2"); + + app.setMainWidget(&tabWidget); + tabWidget.show(); + app.exec(); +} diff --git a/src/app/treeview.cpp b/src/app/treeview.cpp new file mode 100644 index 0000000..ddf24a5 --- /dev/null +++ b/src/app/treeview.cpp @@ -0,0 +1,342 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "treeview.moc" + +// Qt +#include +#include + +// KDE +#include +#include +#include +#include + +// Local +#include "../gvcore/fileoperation.h" + +namespace Gwenview { + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +const int AUTO_OPEN_DELAY=1000; +const int DND_ICON_COUNT=8; +const char* DND_PREFIX="dnd"; + + +struct TreeView::Private { + TreeView* mView; + KFileTreeBranch* mBranch; + KFileTreeViewItem* mDropTarget; + QTimer* mAutoOpenTimer; + + KFileTreeViewItem* findViewItem(KFileTreeViewItem* parent,const QString& text) { + QListViewItem* item; + + for (item=parent->firstChild();item;item=item->nextSibling()) { + if (item->text(0)==text) { + return static_cast(item); + } + } + return 0L; + } + + void setURLInternal(const KURL& url) { + LOG(url.prettyURL() ); + QString path=url.path(); + + if (!mBranch || !mBranch->rootUrl().isParentOf(url)) { + mView->createBranch(url); + return; + } + + // The request URL is a child of the branch, expand the branch to reach + // the child + LOG("Expanding to reach child"); + if(mBranch->rootUrl().path()!="/") { + path.remove(0,mBranch->rootUrl().path().length()); + } + LOG("Path=" << path); + + // Finds the deepest existing view item + QStringList folderParts=QStringList::split('/',path); + QStringList::Iterator folderIter=folderParts.begin(); + QStringList::Iterator endFolderIter=folderParts.end(); + KFileTreeViewItem* viewItem=mBranch->root(); + for(;folderIter!=endFolderIter;++folderIter) { + + KFileTreeViewItem* nextViewItem=findViewItem(viewItem,*folderIter); + if (!nextViewItem) break; + viewItem=nextViewItem; + } + LOG("Deepest existing view item=" << viewItem->url()); + + // If this is the wanted item, select it, + // otherwise set the url as the next to select + if (viewItem->url().equals(url,true)) { + LOG("We are done"); + mView->setCurrentItem(viewItem); + mView->ensureItemVisible(viewItem); + mView->slotSetNextUrlToSelect(KURL()); + } else { + LOG("We continue"); + mView->slotSetNextUrlToSelect(url); + } + + LOG("Opening deepest existing view item"); + viewItem->setOpen(true); + } +}; + + +TreeView::TreeView(QWidget* parent) +: KFileTreeView(parent) { + d=new Private; + d->mView=this; + d->mBranch=0; + d->mDropTarget=0; + d->mAutoOpenTimer=new QTimer(this); + + // Look + addColumn(QString::null); + header()->hide(); + setAllColumnsShowFocus(true); + setRootIsDecorated(false); + setFullWidth(true); + + // Drag'n'drop + setDragEnabled(true); + setDropVisualizer(false); + setDropHighlighter(true); + setAcceptDrops(true); + + connect(d->mAutoOpenTimer, SIGNAL(timeout()), + this, SLOT(autoOpenDropTarget())); +} + + +TreeView::~TreeView() { + delete d; +} + + +void TreeView::setURL(const KURL& url) { + LOG(url.prettyURL()); + if (currentURL().equals(url,true)) return; + if (m_nextUrlToSelect.equals(url,true)) return; + slotSetNextUrlToSelect(url); + + // Do not update the view if it's hidden, the url has been stored with + // slotSetNextUrlToSelect. The view will expand to it next time it's shown. + if (!isVisible()) { + LOG("We are hidden, just store the url"); + return; + } + + d->setURLInternal(url); +} + + +void TreeView::slotTreeViewPopulateFinished(KFileTreeViewItem* item) { + QListViewItem* child; + if (!item) return; + KURL url=item->url(); + + if (d->mDropTarget) { + startAnimation(d->mDropTarget,DND_PREFIX,DND_ICON_COUNT); + } + + LOG("itemURL=" << url); + LOG("m_nextUrlToSelect=" << m_nextUrlToSelect); + + // We reached the URL to select, get out + if (url.equals(m_nextUrlToSelect, true)) { + slotSetNextUrlToSelect(KURL()); + return; + } + + // This URL is not a parent of a wanted URL, get out + if (!url.isParentOf(m_nextUrlToSelect)) return; + + // Find the next child item and open it + LOG("Looking for next child"); + for (child=item->firstChild(); child; child=child->nextSibling()) { + url=static_cast(child)->url(); + if (url.isParentOf(m_nextUrlToSelect)) { + LOG("Opening child with URL=" << url); + ensureItemVisible(child); + child->setOpen(true); + return; + } + } +} + + +void TreeView::createBranch(const KURL& url) { + if (d->mBranch) { + removeBranch(d->mBranch); + } + QString title=url.prettyURL(0, KURL::StripFileProtocol); + d->mBranch=addBranch(url, title, SmallIcon(KMimeType::iconForURL(url)) ); + setDirOnlyMode(d->mBranch, true); + d->mBranch->setChildRecurse(false); + d->mBranch->root()->setOpen(true); + + connect(d->mBranch, SIGNAL(populateFinished(KFileTreeViewItem*) ), + this, SLOT(slotTreeViewPopulateFinished(KFileTreeViewItem*)) ); +} + + + +/** + * Override this method to make sure that the item is selected, opened and + * visible + */ +void TreeView::slotNewTreeViewItems(KFileTreeBranch* branch, const KFileTreeViewItemList& itemList) { + if( ! branch ) return; + LOG(""); + if(m_nextUrlToSelect.isEmpty()) return; + + KFileTreeViewItemListIterator it( itemList ); + + for(;it.current(); ++it ) { + KURL url = (*it)->url(); + + // This is an URL to select + // (We block signals to avoid simulating a click on the dir item) + if (m_nextUrlToSelect.equals(url,true)) { + blockSignals(true); + setCurrentItem(*it); + blockSignals(false); + + ensureItemVisible(*it); + (*it)->setOpen(true); + m_nextUrlToSelect = KURL(); + return; + } + } +} + + +/** + * Override showEvent to make sure the view shows the correct + * dir when it's shown. Since the view doesn't update if it's + * hidden + */ +void TreeView::showEvent(QShowEvent* event) { + LOG("m_nextUrlToSelect=" << m_nextUrlToSelect.pathOrURL()); + if (m_nextUrlToSelect.isValid() && !currentURL().equals(m_nextUrlToSelect,true)) { + d->setURLInternal(m_nextUrlToSelect); + } + QWidget::showEvent(event); +} + + +void TreeView::contentsDragMoveEvent(QDragMoveEvent* event) { + if (!KURLDrag::canDecode(event)) { + event->ignore(); + return; + } + + // Get a pointer to the new drop item + QPoint point(0,event->pos().y()); + KFileTreeViewItem* newDropTarget=static_cast( itemAt(contentsToViewport(point)) ); + if (!newDropTarget) { + event->ignore(); + d->mAutoOpenTimer->stop(); + if (d->mDropTarget) { + stopAnimation(d->mDropTarget); + d->mDropTarget=0L; + } + return; + } + + event->accept(); + if (newDropTarget==d->mDropTarget) return; + if (d->mDropTarget) { + stopAnimation(d->mDropTarget); + } + + // Restart auto open timer if we are over a new item + d->mAutoOpenTimer->stop(); + d->mDropTarget=newDropTarget; + startAnimation(newDropTarget,DND_PREFIX,DND_ICON_COUNT); + d->mAutoOpenTimer->start(AUTO_OPEN_DELAY,true); +} + + +void TreeView::contentsDragLeaveEvent(QDragLeaveEvent*) { + d->mAutoOpenTimer->stop(); + if (d->mDropTarget) { + stopAnimation(d->mDropTarget); + d->mDropTarget=0L; + } +} + + +void TreeView::contentsDropEvent(QDropEvent* event) { + d->mAutoOpenTimer->stop(); + + // Get data from drop (do it before showing menu to avoid mDropTarget changes) + if (!d->mDropTarget) return; + KURL dest=d->mDropTarget->url(); + + KURL::List urls; + if (!KURLDrag::decode(event,urls)) return; + + // Show popup + bool wasMoved; + FileOperation::openDropURLMenu(this, urls, dest, &wasMoved); + + if (wasMoved) { + // If the current url was in the list, set the drop target as the new + // current item + KURL current=currentURL(); + KURL::List::ConstIterator it=urls.begin(); + for (; it!=urls.end(); ++it) { + if (current.equals(*it,true)) { + setCurrentItem(d->mDropTarget); + break; + } + } + } + + // Reset drop target + if (d->mDropTarget) { + stopAnimation(d->mDropTarget); + d->mDropTarget=0L; + } +} + + +void TreeView::autoOpenDropTarget() { + if (d->mDropTarget) { + d->mDropTarget->setOpen(true); + } +} +} // namespace diff --git a/src/app/treeview.h b/src/app/treeview.h new file mode 100644 index 0000000..e0c41c2 --- /dev/null +++ b/src/app/treeview.h @@ -0,0 +1,70 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2005 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef TREEVIEW_H +#define TREEVIEW_H + +// KDE +#include + +class KURL; +class QShowEvent; + +namespace Gwenview { + + +class TreeView : public KFileTreeView { +Q_OBJECT +public: + TreeView(QWidget* parent); + ~TreeView(); + +public slots: + void setURL(const KURL&); + void createBranch(const KURL&); + +signals: + void urlChanged(const KURL&); + +protected: + virtual void showEvent(QShowEvent*); + virtual void contentsDragMoveEvent(QDragMoveEvent*); + virtual void contentsDragLeaveEvent(QDragLeaveEvent*); + virtual void contentsDropEvent(QDropEvent*); + +protected slots: + virtual void slotNewTreeViewItems(KFileTreeBranch*, const KFileTreeViewItemList&); + +private: + struct Private; + Private* d; + friend class Private; + +private slots: + // Do not name this slot "slotPopulateFinished", it will clash with + // "KFileTreeView::slotPopulateFinished". + void slotTreeViewPopulateFinished(KFileTreeViewItem*); + + void autoOpenDropTarget(); +}; + + +} // namespace +#endif diff --git a/src/app/truncatedtextlabel.h b/src/app/truncatedtextlabel.h new file mode 100644 index 0000000..81298fd --- /dev/null +++ b/src/app/truncatedtextlabel.h @@ -0,0 +1,79 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef TRUNCATEDTEXTLABEL_H +#define TRUNCATEDTEXTLABEL_H + +// Qt +#include +#include + +// KDE +#include + +namespace Gwenview { + +/** + * A label which truncates it's text if it's too long, drawing it using + * KWordWrap::drawFadeoutText() + */ +class TruncatedTextLabel : public QLabel { +public: + TruncatedTextLabel(QWidget* parent) + : QLabel(parent) {} + + QSize minimumSizeHint() const { + QSize size=QLabel::minimumSizeHint(); + size.setWidth(-1); + return size; + } + + QSize sizeHint() const { + return QSize(contentsRect().width(), QLabel::sizeHint().height()); + } + + void setText(const QString& text) { + QLabel::setText(text); + updateToolTip(); + } + +protected: + void drawContents(QPainter* painter) { + KWordWrap::drawFadeoutText(painter, 0, fontMetrics().ascent(), width(), text()); + } + + void resizeEvent(QResizeEvent*) { + updateToolTip(); + } + + void updateToolTip() { + QString txt=text(); + QToolTip::remove(this); + if ( width() < fontMetrics().width(txt) ) { + QToolTip::add(this, txt); + } else { + QToolTip::hide(); + } + } +}; + +} // namespace + +#endif /* TRUNCATEDTEXTLABEL_H */ diff --git a/src/app/vtabwidget.cpp b/src/app/vtabwidget.cpp new file mode 100644 index 0000000..974dc00 --- /dev/null +++ b/src/app/vtabwidget.cpp @@ -0,0 +1,85 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +// kate: indent-mode csands; indent-width 4; replace-tabs-save off; replace-tabs off; replace-trailing-space-save off; space-indent off; tabs-indents on; tab-width 4; +/* +Gwenview - A simple image viewer for KDE +Copyright 2005 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "vtabwidget.moc" + +// Qt +#include + +// KDE +#include + +namespace Gwenview { + + +struct VTabWidget::Private { + KMultiTabBar* mTabBar; + QWidgetStack* mStack; + bool mEmpty; +}; + + +VTabWidget::VTabWidget(QWidget* parent) +: QWidget(parent) +{ + d=new Private; + d->mEmpty=true; + d->mTabBar=new KMultiTabBar(KMultiTabBar::Vertical, this); + d->mTabBar->setPosition(KMultiTabBar::Left); + d->mTabBar->setStyle(KMultiTabBar::KDEV3ICON); + d->mStack=new QWidgetStack(this); + QHBoxLayout* layout=new QHBoxLayout(this); + layout->add(d->mTabBar); + layout->add(d->mStack); +} + + +VTabWidget::~VTabWidget() { + delete d; +} + + +void VTabWidget::addTab(QWidget* child, const QPixmap& pix, const QString& label) { + int id=d->mStack->addWidget(child); + d->mTabBar->appendTab(pix, id, label); + connect(d->mTabBar->tab(id), SIGNAL(clicked(int)), + this, SLOT(slotClicked(int)) ); + + if (d->mEmpty) { + d->mTabBar->tab(id)->setOn(true); + d->mEmpty=false; + } +} + + +void VTabWidget::slotClicked(int id) { + d->mStack->raiseWidget(id); + QPtrList* tabs=d->mTabBar->tabs(); + QPtrListIterator it(*tabs); + for (; it.current(); ++it) { + KMultiTabBarTab* tab=it.current(); + tab->setOn(tab->id()==id); + } +} + + +} // namespace diff --git a/src/app/vtabwidget.h b/src/app/vtabwidget.h new file mode 100644 index 0000000..0f177ec --- /dev/null +++ b/src/app/vtabwidget.h @@ -0,0 +1,52 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +// kate: indent-mode csands; indent-width 4; replace-tabs-save off; replace-tabs off; replace-trailing-space-save off; space-indent off; tabs-indents on; tab-width 4; +/* +Gwenview - A simple image viewer for KDE +Copyright 2005 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef VTABWIDGET_H +#define VTABWIDGET_H + +// Qt +#include + +class QPixmap; + +namespace Gwenview { + + +class VTabWidget : public QWidget { +Q_OBJECT +public: + VTabWidget(QWidget* parent); + virtual ~VTabWidget(); + void addTab(QWidget*, const QPixmap&, const QString& label); + +private slots: + void slotClicked(int id); + +private: + struct Private; + Private* d; +}; + + +} // namespace + + +#endif /* VTABWIDGET_H */ diff --git a/src/configure.in.bot b/src/configure.in.bot new file mode 100644 index 0000000..ed010db --- /dev/null +++ b/src/configure.in.bot @@ -0,0 +1,11 @@ +if test "$want_kipi" = "yes" ; then + if test "$have_kipi" != "yes" ; then + echo "" + echo "KIPI is not installed. Gwenview will be build without KIPI support." + echo "" + fi +else + echo "" + echo "KIPI support has been disabled. Gwenview will be build without KIPI support." + echo "" +fi diff --git a/src/desktopfiles/Makefile.am b/src/desktopfiles/Makefile.am new file mode 100644 index 0000000..d36dea4 --- /dev/null +++ b/src/desktopfiles/Makefile.am @@ -0,0 +1,9 @@ +# this is where the kdelnk file will go +xdg_apps_DATA = gwenview.desktop + +# file for konqueror integration +konqservicedir = $(kde_datadir)/konqueror/servicemenus +konqservice_DATA = konqgwenview.desktop + + +EXTRA_DIST = $(xdg_apps_DATA) $(konqservice_DATA) diff --git a/src/desktopfiles/gwenview.desktop b/src/desktopfiles/gwenview.desktop new file mode 100644 index 0000000..9aec864 --- /dev/null +++ b/src/desktopfiles/gwenview.desktop @@ -0,0 +1,107 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Gwenview +Name[hi]=ग्वेनव्यू +Name[ta]=gwen பார்வை +Name[tg]=НамоишиGwen +Name[xx]=xxGwenviewxx +GenericName=Image Viewer +GenericName[bg]=Преглед на изображения +GenericName[br]=Gweler ar skeudennoù +GenericName[bs]=Preglednik slika +GenericName[ca]=Visor d'imatges +GenericName[cs]=Prohlížeč obrázků +GenericName[cy]=Gwelydd Delwedd +GenericName[da]=Billedfremviser +GenericName[de]=Bildbetrachter +GenericName[el]=Προβολέας εικόνων +GenericName[es]=Visualizador de imágenes +GenericName[et]=Pildinäitaja +GenericName[fa]=مشاهده‌گر تصویر +GenericName[fi]=Kuvankatseluohjelma +GenericName[fr]=Afficheur d'images +GenericName[gl]=Visor de Imaxes +GenericName[hi]=छवि प्रदर्शक +GenericName[hr]=Preglednik slika +GenericName[hu]=Képnézegető +GenericName[is]=Myndskoðari +GenericName[it]=Visualizzatore di immagini +GenericName[ja]=画像ビューア +GenericName[ka]=სურათების დამთვალიერებელი +GenericName[lt]=Paveikslėlių žiūriklis +GenericName[ms]=Pelihat Imej +GenericName[nds]=Bildkieker +GenericName[nl]=Afbeeldingweergaveprogramma +GenericName[pa]=ਚਿੱਤਰ ਦਰਸ਼ਕ +GenericName[pl]=Przeglądarka obrazków +GenericName[pt]=Visualizador de Imagens +GenericName[pt_BR]=Visualizador de Imagens +GenericName[ru]=Просмотр изображений +GenericName[rw]=Mugaraza Shusho +GenericName[sk]=Prehliadač obrázkov +GenericName[sl]=Pregledovalnik slik +GenericName[sr]=Приказивач слика +GenericName[sr@Latn]=Prikazivač slika +GenericName[sv]=Bildvisning +GenericName[tg]=Намоишгари тасвир +GenericName[tr]=Resim Gösterici +GenericName[uk]=Переглядач зображень +GenericName[vi]=Bộ xem ảnh +GenericName[xh]=Umboniseli Womfanekiso +GenericName[xx]=xxImage Viewerxx +GenericName[zh_CN]=图像查看器 +GenericName[zu]=Umbonisi Womfanekiso +Comment=A simple image viewer +Comment[ar]=مستعرض الصور البسيط +Comment[bg]=Малка програма за преглед на изображения +Comment[br]=Ur gweler skeudenn eeun +Comment[bs]=Jednostavan preglednik slika +Comment[ca]=Un visor d'imatges senzill +Comment[cs]=Jednoduchý prohlížeč obrázků +Comment[da]=En simpel billedfremviser +Comment[de]=Ein einfacher Bildbetrachter +Comment[el]=Ένας απλός προβολέας εικόνων +Comment[es]=Visor de mensajes sencillo +Comment[et]=Lihtne pildinäitaja +Comment[fa]=یک مشاهده‌گر تصویر ساده +Comment[fi]=Yksinkertainen kuvankatseluohjelma +Comment[fr]=Un afficheur basique d'images +Comment[gl]=Un visor de imaxes +Comment[he]=מציג תמונות פשוט +Comment[hi]=एक सरल चित्र प्रदर्शक +Comment[hr]=Jednostavan preglednik slika +Comment[hu]=Egyszerű képnézegető +Comment[is]=Einfaldur myndskoðari +Comment[it]=Semplice visualizzatore di immagini +Comment[ja]=シンプルな画像ビューア +Comment[ka]=სურათების მარტივი დამთვალიერებელი +Comment[ms]=Pelihat imej ringkas +Comment[nds]=En eenfach Bildkieker +Comment[nl]=Een eenvoudig afbeeldingenweergaveprogramma +Comment[pa]=ਇੱਕ ਸਧਾਰਨ ਚਿੱਤਰ ਦਰਸ਼ਕ +Comment[pl]=Prosta przeglądarka obrazków +Comment[pt]=Um visualizador de imagens simples +Comment[pt_BR]=Um visualizador de imagens simples +Comment[ru]=Простая программа просмотра изображений +Comment[sk]=Jednoduchý prehliadač obrázkov +Comment[sl]=Preprost pregledovalnik slik +Comment[sr]=Једноставан приказивач слика +Comment[sr@Latn]=Jednostavan prikazivač slika +Comment[sv]=En enkel bildvisare +Comment[ta]=ஒரு சாதாரண உருவ பார்வையாளர் +Comment[tg]=Барномаи оддӣ барои намоиши тасвир +Comment[tr]=Basit bir resim izleyici +Comment[uk]=Простий переглядач зображень +Comment[vi]=Bộ xem ảnh đơn giản +Comment[xh]=Umboniseli olula womfanekiso +Comment[xx]=xxA simple image viewerxx +Comment[zh_CN]=一个简单的图像查看器 +Comment[zh_TW]=一個簡易的影像檢視器 +Comment[zu]=Umbukisi wesithombe esilula +Exec=gwenview %u -caption "%c" %i %m +Terminal=false +Icon=gwenview +Type=Application +Categories=Qt;KDE;Graphics; +MimeType=image/gif;image/x-xpm;image/x-xbm;image/jpeg;image/x-pcx;image/x-bmp;image/png;image/x-ico;image/x-portable-bitmap;image/x-portable-pixmap;image/x-portable-greymap;image/tiff;image/x-targa; +DocPath=gwenview/index.html diff --git a/src/desktopfiles/konqgwenview.desktop b/src/desktopfiles/konqgwenview.desktop new file mode 100644 index 0000000..cf6f2d8 --- /dev/null +++ b/src/desktopfiles/konqgwenview.desktop @@ -0,0 +1,55 @@ +[Desktop Entry] +Encoding=UTF-8 +ServiceTypes=inode/directory +Actions=gwenview; + +[Desktop Action gwenview] +Name=Browse with Gwenview +Name[ar]=تصفح بواسطة Gwenview +Name[bg]=Преглед с Gwenview +Name[br]=Furchal gant Gwenview +Name[bs]=Pregledaj sa Gwenview +Name[ca]=Navega amb el Gwenview +Name[cs]=Prohlížet pomocí Gwenview +Name[da]=Gennemse med Gwenview +Name[de]=Dateien mit Gwenview durchsehen +Name[el]=Εξερεύνηση με το Gwenview +Name[es]=Navegación con Gwenview +Name[et]=Lehitse kasutades Gwenview'd +Name[fa]=مرور با Gwenview +Name[fi]=Katsele Gwenviewilla +Name[fr]=Naviguer avec Gwenview +Name[gl]=Examinar con Gwenview +Name[he]=עיין בעזרת Gwenview +Name[hi]=ग्वेनव्यू के साथ ब्राउज़ करें +Name[hr]=Pretraži s Gwenview +Name[hu]=Böngészés a Gwenview-val +Name[is]=Skoða með Gwenview +Name[it]=Sfoglia con Gwenview +Name[ja]=Gwenview で閲覧 +Name[ka]=დათვალიერება Gwenview-ით +Name[ms]= Lungsur dengan Gwenview +Name[nds]=Dateien mit Gwenview dörkieken +Name[nl]=Bladeren met Gwenview +Name[pa]=Gwenview ਨਾਲ ਵੇਖੋ +Name[pl]=Przeglądaj za pomocą Gwenview +Name[pt]=Navegar com o Gwenview +Name[pt_BR]=Navegar com Gwenview +Name[ru]=Просмотреть в Gwenview +Name[sk]=Prehliadať s Gwenview +Name[sl]=Brskaj z Gwenview +Name[sr]=Прегледај помоћу Gwenview-а +Name[sr@Latn]=Pregledaj pomoću Gwenview-a +Name[sv]=Bläddra med Gwenview +Name[ta]=GWEN பார்வையை வைத்து தேடு +Name[tg]=Ҷустан бо НамоишиGwen +Name[tr]=Gwenview ile gözat +Name[uk]=Перегляд у Gwenview +Name[vi]=Duyệt bằng Gwenview +Name[xh]=Khangela nge Gwenview +Name[xx]=xxBrowse with Gwenviewxx +Name[zh_CN]=用 Gwenview 浏览 +Name[zh_TW]=以 Gwenview 瀏覽 +Name[zu]=Cinga nge-Gwenview +Icon=gwenview +Exec=gwenview %u diff --git a/src/doc/Makefile.am b/src/doc/Makefile.am new file mode 100644 index 0000000..a34ff18 --- /dev/null +++ b/src/doc/Makefile.am @@ -0,0 +1 @@ +man_MANS = gwenview.1 diff --git a/src/doc/gwenview.1 b/src/doc/gwenview.1 new file mode 100644 index 0000000..e39b41c --- /dev/null +++ b/src/doc/gwenview.1 @@ -0,0 +1,238 @@ +.TH GWENVIEW 1 "January 2005" "K Desktop Environment" "Image viewer for KDE" +.SH NAME +Gwenview \- An image viewer for KDE +.SH SYNOPSIS +.B gwenview +[\fIoptions\fR] [\fIfile or folder\fR] +.SH DESCRIPTION +Gwenview is an image viewer for KDE. It features a folder tree window and a file list window to provide easy navigation of your file hierarchy. Gwenview uses docked windows, so you can alter its layout any way you wish. You can also browse your images in full\-screen mode, or embedded within Konqueror using the Gwenview Image Browser View and Kpart. +.PP +Image loading is handled by the Qt library, so Gwenview supports all image formats your Qt installation supports. Gwenview correctly displays images with an alpha channel. +.PP +Gwenview supports the displaying and editing of EXIF comments, if the necessary JPEG kfile\-plugin is installed. This comes as part of the kdegraphics package. Lossless JPEG transforms are also supported. +.SH OPTIONS +.SS Arguments: +.TP +.B file or folder +An initial image file, or a folder containing images. +.SS Gwenview options: +.TP +.B \-f +Start in Full Screen mode. +.SS Generic options: +.TP +.B \-\-help +Show help about options. +.TP +.B \-\-help\-qt +Show Qt specific options. +.TP +.B \-\-help\-kde +Show KDE specific options. +.TP +.B \-\-help\-all +Show all options. +.TP +.B \-\-author +Show author information. +.TP +.B \-v\fR, \fB\-\-version +Show version information. +.TP +.B \-\-license +Show license information. +.TP +.B \-\- +End of options. +.SS Qt options: +.TP +.B \-\-display \fIdisplayname\fR +Use the X\-server display 'displayname'. +.TP +.B \-\-session \fIsessionId\fR +Restore the application for the given 'sessionId'. +.TP +.B \-\-cmap +Causes the application to install a private color +map on an 8\-bit display. +.TP +.B \-\-ncols \fIcount\fR +Limits the number of colors allocated in the color +cube on an 8\-bit display, if the application is +using the QApplication::ManyColor color +specification. +.TP +.B \-\-nograb +Tells Qt to never grab the mouse or the keyboard. +.TP +.B \-\-dograb +Running under a debugger can cause an implicit +\-nograb, use \-dograb to override. +.TP +.B \-\-sync +Switches to synchronous mode for debugging. +.TP +.B \-\-fn\fR, \fB\-\-font \fIfontname\fR +Defines the application font. +.TP +.B \-\-bg\fR, \fB\-\-background \fIcolor\fR +Sets the default background color and an +application palette (light and dark shades are +calculated). +.TP +.B \-\-fg\fR, \fB\-\-foreground \fIcolor\fR +Sets the default foreground color. +.TP +.B \-\-btn\fR, \fB\-\-button \fIcolor\fR +Sets the default button color. +.TP +.B \-\-name \fIname\fR +Sets the application name. +.TP +.B \-\-title \fItitle\fR +Sets the application title (caption). +.TP +.B \-\-visual TrueColor +Forces the application to use a TrueColor visual on +an 8\-bit display. +.TP +.B \-\-inputstyle \fIinputstyle\fR +Sets XIM (X Input Method) input style. Possible +values are onthespot, overthespot, offthespot and +root. +.TP +.B \-\-im \fIXIM server\fR +Set XIM server. +.TP +.B \-\-noxim +Disable XIM. +.TP +.B \-\-reverse +Mirrors the whole layout of widgets. +.SS KDE options: +.TP +.B \-\-caption \fIcaption\fR +Use 'caption' as name in the titlebar. +.TP +.B \-\-icon \fIicon\fR +Use 'icon' as the application icon. +.TP +.B \-\-miniicon \fIicon\fR +Use 'icon' as the icon in the titlebar. +.TP +.B \-\-config \fIfilename\fR +Use alternative configuration file. +.TP +.B \-\-dcopserver \fIserver\fR +Use the DCOP Server specified by 'server'. +.TP +.B \-\-nocrashhandler +Disable crash handler, to get core dumps. +.TP +.B \-\-waitforwm +Waits for a WM_NET compatible windowmanager. +.TP +.B \-\-style \fIstyle\fR +Sets the application GUI style. +.TP +.B \-\-geometry \fIgeometry\fR +Sets the client geometry of the main widget. +.SH INTERFACE +.SS Browse and View modes +By default, Gwenview opens in Browse mode, with the docked windows (showing +directory structure and contents) displayed. Starting Gwenview with a directory +as an argument also begins in Browse mode. Starting with an image as an argument, +however, opens Gwenview in View mode, with these docked windows hidden to give +full space to the image itself. +.PP +Once Gwenview is started, the user can toggle between Browse and View modes by +clicking the Browse button on the Main Toolbar. The same option can be found +in the View menu. Ctrl-Return will toggle these modes as well. +.PP +Whereas normally, in Browse mode, single-clicking on an image thumbnail or +listing is sufficient for Gwenview to display it, users also have the option of +double-clicking, which displays the image and switches Gwenview to View mode. +.SS Docked windows +The Gwenview interface is composed of a number of smaller docked windows. +Manipulating these windows can be difficult at first. To focus a particular +window in the Gwenview interface, simply click within it. +.PP +Each docked window has a small grip bar along the top, with a dock/undock button +resembling an arrow at its right end, as well as a close button resembling the +letter X. +.PP +Clicking the close button on a docked window will remove it from the interface. +To bring back a window, select it from the Window menu. +.PP +To resize docked windows, click on the border between the windows, and drag. +To re-arrange the docked windows, click on a window's grip bar along its top, and drag +the window over to the desired position relative to the other docked windows. +While dragging, a small box outline should appear that indicates the new position +that the window will take, when you release the mouse and end the drag. If you wish +to stack two windows, and use tabs to choose between them, drag the window to the +very center of the other window with which you wish to stack. +.PP +To undock a window, either click the dock/undock button in its top right corner, or +double-click on the window's grip bar. Double-clicking again, or clicking +on the dock/undock button, should return the window to its original position. +Otherwise, you can dock an undocked window by dragging its grip bar back to a +point within the general interface, just as if you were rearranging an already +docked window. +.PP +The file view window cannot be undocked or moved, but by moving other windows +around, it can itself be shifted about. +.PP +While dragging a window, press the Escape key to cancel the operation. To reset +the docked windows to the default Gwenview layout, use the Reset option in the +Window menu. +.SS Mouse operations +Browsing a directory of images can be done several ways, including mouse +gestures. Hold down the left mouse button over an image, then click the right +button to go to the next image. Hold down the right button, then click the +left button to load the previous image. +.PP +Clicking the right mouse button on an image brings up a context menu. +.PP +Clicking the middle mouse button will toggle the auto zoom on/off. +.PP +Double-clicking on an image toggles Full Screen mode. +.PP +Holding down the left mouse button on an image allows you to +scroll the image. By default, you can also scroll up and down an image by +using the mouse wheel. However, this can be configured to browse the images +in the current directory instead. +.PP +The mouse wheel, used while holding down the Shift key, will zoom the image +in and out. +.PP +The mouse wheel, used while holding down the Control or Alt keys, will scroll the image horizontally. +.SS Keybindings +Gwenview comes with a range of keyboard shortcuts, all of which can be viewed and remapped by +selecting "Configure Shortcuts" in the Settings menu. Note that in the Files and Folders windows, +all the normal KDE shortcuts are functional, unless otherwise remapped. +.PP +A few of the most useful default bindings are: +.PP + Ctrl-Shift-F Toggles Full Screen mode. + Escape Stop, exit from Full Screen mode. + + Home Displays the first image in the directory. + End Displays the last image in the directory. + + Space Displays the next image in the directory. + Backspace Displays the previous image in the directory. +.SH "SEE ALSO" +The Gwenview homepage can be found at \fIhttp://gwenview.sourceforge.net\fR. +.PP +A mailing list is also available at \fIhttp://lists.sourceforge.net/lists/listinfo/gwenview-general\fR. +.SH BUGS +To report a bug, please visit \fIhttp://bugs.kde.org\fR. +.SH AUTHOR +Gwenview was written by Aurelien Gateau . +.PP +This manual page was written by Christopher Martin for +Debian GNU/Linux, but may be used by others. +.PP +Permission is granted to copy, distribute and/or modify this document under the +terms of the GNU General Public License, Version 2, any later version published +by the Free Software Foundation. diff --git a/src/gvcore/.vimrc b/src/gvcore/.vimrc new file mode 100644 index 0000000..a37475c --- /dev/null +++ b/src/gvcore/.vimrc @@ -0,0 +1,4 @@ +set tabstop=4 +set shiftwidth=4 +set noexpandtab +set makeprg=unsermake diff --git a/src/gvcore/Makefile.am b/src/gvcore/Makefile.am new file mode 100644 index 0000000..1bec46b --- /dev/null +++ b/src/gvcore/Makefile.am @@ -0,0 +1,85 @@ +AM_CPPFLAGS = -I$(srcdir)/.. $(all_includes) -D_LARGEFILE64_SOURCE + +lib_LTLIBRARIES = libgwenviewcore.la + +libgwenviewcore_la_LDFLAGS = $(all_libraries) -version-info 1:0:0 -no-undefined + +libgwenviewcore_la_LIBADD = \ + $(LIB_KFILE) $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_KDEPRINT) $(LIB_QT) \ + $(LIBJPEG) $(LIBPNG) $(LIBMNG) $(GV_LIB_XCURSOR) $(LIB_EXIV2)\ + -lkmediaplayer ../imageutils/libgvimageutils.la \ + ../tsthread/libtsthread.la + +libgwenviewcore_la_METASOURCES = AUTO + +noinst_HEADERS = libgwenview_export.h + +# Be sure to keep pngformattype.cpp first, to avoid troubles with --enable-final +# See bug #134919 +libgwenviewcore_la_SOURCES = \ + pngformattype.cpp \ + printdialog.cpp \ + printdialogpagebase.ui \ + thumbnailloadjob.cpp \ + imageview.cpp \ + imageviewcontroller.cpp \ + document.cpp \ + externaltoolmanager.cpp \ + externaltoolcontext.cpp \ + externaltoolaction.cpp \ + externaltooldialogbase.ui \ + externaltooldialog.cpp \ + fileviewcontroller.cpp \ + filethumbnailview.cpp \ + fileoperation.cpp \ + fileopobject.cpp \ + filethumbnailviewitem.cpp \ + filterbar.ui \ + qxcfi.cpp \ + archive.cpp \ + slideshow.cpp \ + filedetailview.cpp \ + filedetailviewitem.cpp \ + imagesavedialog.cpp \ + jpegformattype.cpp \ + mngformattype.cpp \ + xpm.cpp \ + documentimpl.cpp \ + documentloadingimpl.cpp \ + documentloadedimpl.cpp \ + documentjpegloadedimpl.cpp \ + documentanimatedloadedimpl.cpp \ + documentotherloadedimpl.cpp \ + busylevelmanager.cpp \ + cache.cpp \ + threadgate.cpp \ + imageviewtools.cpp \ + fullscreenbar.cpp \ + imageloader.cpp \ + cursortracker.cpp \ + captionformatter.cpp \ + thumbnaildetailsdialogbase.ui \ + thumbnaildetailsdialog.cpp \ + xcursor.cpp \ + mimetypeutils.cpp \ + bcgdialog.cpp \ + bcgdialogbase.ui \ + timeutils.cpp \ + clicklineedit.cpp \ + inputdialog.cpp \ + deletedialog.cpp \ + deletedialogbase.ui \ + miscconfig.kcfgc \ + slideshowconfig.kcfgc \ + fileoperationconfig.kcfgc \ + fullscreenconfig.kcfgc \ + imageviewconfig.kcfgc \ + fileviewconfig.kcfgc + +kde_kcfg_DATA = \ + miscconfig.kcfg \ + slideshowconfig.kcfg \ + fileoperationconfig.kcfg \ + fullscreenconfig.kcfg \ + imageviewconfig.kcfg \ + fileviewconfig.kcfg diff --git a/src/gvcore/archive.cpp b/src/gvcore/archive.cpp new file mode 100644 index 0000000..d31d1a7 --- /dev/null +++ b/src/gvcore/archive.cpp @@ -0,0 +1,87 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// KDE includes +#include + +// Our includes +#include "archive.h" +namespace Gwenview { + + +namespace Archive { + +typedef QMap MimeTypeProtocols; + +static const char* KDE_PROTOCOL = "X-KDE-LocalProtocol"; + +static const MimeTypeProtocols& mimeTypeProtocols() { + static MimeTypeProtocols map; + if (map.isEmpty()) { + KMimeType::List list = KMimeType::allMimeTypes(); + KMimeType::List::Iterator it=list.begin(), end=list.end(); + for (; it!=end; ++it) { + if ( (*it)->propertyNames().findIndex(KDE_PROTOCOL)!= -1 ) { + QString protocol = (*it)->property(KDE_PROTOCOL).toString(); + map[(*it)->name()] = protocol; + } + } + } + return map; +} + + +bool fileItemIsArchive(const KFileItem* item) { + return mimeTypeProtocols().contains(item->mimetype()); +} + +bool fileItemIsDirOrArchive(const KFileItem* item) { + return item->isDir() || Archive::fileItemIsArchive(item); +} + +bool protocolIsArchive(const QString& protocol) { + const MimeTypeProtocols& map=mimeTypeProtocols(); + MimeTypeProtocols::ConstIterator it; + for (it=map.begin();it!=map.end();++it) { + if (it.data()==protocol) return true; + } + return false; +} + +QStringList mimeTypes() { + const MimeTypeProtocols& map=mimeTypeProtocols(); + MimeTypeProtocols::ConstIterator it; + QStringList strlist; + for (it=map.begin();it!=map.end();++it) { + strlist+=it.key(); + } + return strlist; + //return mimeTypeProtocols().keys(); // keys() does not exist in Qt 3.0 +} + + +QString protocolForMimeType(const QString& mimeType) { + return mimeTypeProtocols()[mimeType]; +} + +} + +} // namespace diff --git a/src/gvcore/archive.h b/src/gvcore/archive.h new file mode 100644 index 0000000..cc98ced --- /dev/null +++ b/src/gvcore/archive.h @@ -0,0 +1,46 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef ARCHIVE_H +#define ARCHIVE_H + +// Qt includes +#include +#include "libgwenview_export.h" +class KFileItem; +namespace Gwenview { + +/** + * Helper functions to deal with archives + */ +namespace Archive { + +LIBGWENVIEW_EXPORT bool fileItemIsArchive(const KFileItem*); +LIBGWENVIEW_EXPORT bool fileItemIsDirOrArchive(const KFileItem*); +bool protocolIsArchive(const QString&); +QStringList mimeTypes(); +QString protocolForMimeType(const QString&); + +} + +} // namespace +#endif + diff --git a/src/gvcore/bcgdialog.cpp b/src/gvcore/bcgdialog.cpp new file mode 100644 index 0000000..18b7822 --- /dev/null +++ b/src/gvcore/bcgdialog.cpp @@ -0,0 +1,84 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2006 Aurélien Gâteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Self +#include "bcgdialog.moc" + +// Qt +#include +#include + +// KDE +#include + +// Local +#include "imageview.h" +#include "bcgdialogbase.h" + +namespace Gwenview { + + +struct BCGDialog::Private { + ImageView* mView; + BCGDialogBase* mContent; +}; + + +BCGDialog::BCGDialog(ImageView* view) +: KDialogBase(view, "bcg_dialog", false /* modal */, + i18n("Adjust Brightness/Contrast/Gamma"), KDialogBase::Close | KDialogBase::Default) +{ + d=new Private; + d->mView=view; + d->mContent=new BCGDialogBase(this); + setMainWidget(d->mContent); + connect(d->mContent->mBSlider, SIGNAL(valueChanged(int)), + view, SLOT(setBrightness(int)) ); + connect(d->mContent->mCSlider, SIGNAL(valueChanged(int)), + view, SLOT(setContrast(int)) ); + connect(d->mContent->mGSlider, SIGNAL(valueChanged(int)), + view, SLOT(setGamma(int)) ); + + connect(view, SIGNAL(bcgChanged()), + this, SLOT(updateFromImageView()) ); +} + + +BCGDialog::~BCGDialog() { + delete d; +} + + +void BCGDialog::slotDefault() { + d->mView->setBrightness(0); + d->mView->setContrast(0); + d->mView->setGamma(0); + updateFromImageView(); +} + + +void BCGDialog::updateFromImageView() { + d->mContent->mBSlider->setValue(d->mView->brightness()); + d->mContent->mCSlider->setValue(d->mView->contrast()); + d->mContent->mGSlider->setValue(d->mView->gamma()); +} + + +} // namespace diff --git a/src/gvcore/bcgdialog.h b/src/gvcore/bcgdialog.h new file mode 100644 index 0000000..4093320 --- /dev/null +++ b/src/gvcore/bcgdialog.h @@ -0,0 +1,53 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2006 Aurélien Gâteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef BCGDIALOG_H +#define BCGDIALOG_H + +// KDE +#include + +class QShowEvent; + +namespace Gwenview { + +class ImageView; + +class BCGDialog : public KDialogBase { +Q_OBJECT +public: + BCGDialog(ImageView*); + ~BCGDialog(); + +protected: + virtual void slotDefault(); + +private slots: + void updateFromImageView(); + +private: + struct Private; + Private* d; +}; + + +} // namespace + +#endif /* BCGDIALOG_H */ diff --git a/src/gvcore/bcgdialogbase.ui b/src/gvcore/bcgdialogbase.ui new file mode 100644 index 0000000..81a79a3 --- /dev/null +++ b/src/gvcore/bcgdialogbase.ui @@ -0,0 +1,179 @@ + +BCGDialogBase + + + BCGDialogBase + + + + 0 + 0 + 377 + 140 + + + + + unnamed + + + 0 + + + + textLabel2 + + + &Contrast: + + + mCSlider + + + + + textLabel2_2 + + + &Gamma: + + + mGSlider + + + + + mBSlider + + + -100 + + + 100 + + + Horizontal + + + + + mCSlider + + + -100 + + + 100 + + + Horizontal + + + + + mGSlider + + + -100 + + + 100 + + + Horizontal + + + + + mBSpinBox + + + 100 + + + -100 + + + + + mCSpinBox + + + 100 + + + -100 + + + + + mGSpinBox + + + 100 + + + -100 + + + + + textLabel1 + + + &Brightness: + + + mBSlider + + + + + + + mBSlider + valueChanged(int) + mBSpinBox + setValue(int) + + + mCSlider + valueChanged(int) + mCSpinBox + setValue(int) + + + mGSlider + valueChanged(int) + mGSpinBox + setValue(int) + + + mBSpinBox + valueChanged(int) + mBSlider + setValue(int) + + + mCSpinBox + valueChanged(int) + mCSlider + setValue(int) + + + mGSpinBox + valueChanged(int) + mGSlider + setValue(int) + + + + mBSlider + mBSpinBox + mCSlider + mCSpinBox + mGSlider + mGSpinBox + + + diff --git a/src/gvcore/busylevelmanager.cpp b/src/gvcore/busylevelmanager.cpp new file mode 100644 index 0000000..adfdf55 --- /dev/null +++ b/src/gvcore/busylevelmanager.cpp @@ -0,0 +1,108 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// Qt +#include + +// KDE +#include + +// Local +#include "busylevelmanager.moc" +namespace Gwenview { + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +BusyLevelManager::BusyLevelManager() +: mCurrentBusyLevel( BUSY_NONE ) +{ + connect( &mDelayedBusyLevelTimer, SIGNAL( timeout()), + this, SLOT( delayedBusyLevelChanged())); +} + +BusyLevelManager* BusyLevelManager::instance() { + static BusyLevelManager manager; + return &manager; +} + +// How the busy level stuff works: +// This system allows suspending less important tasks while more important +// task are active, i.e. no thumbnails are generated when the viewed +// image is being loaded and painted. +// All objects responsible for operations set their busy level +// to the matching value when the operation starts and reset their busy +// level when the operation is done. They all connect to busyLevelChanged() +// signal and suspend their operation if the current busy level is higher +// than the busy level of their operation. If a new operation is started, +// it needs to be immediatelly suspended if the current busy level is higher! +// Note that there can be only one level per object, +// so if one object is responsible for more operations, +// it needs to use helper objects for setBusyLevel(). + +void BusyLevelManager::setBusyLevel( QObject* obj, BusyLevel level ) { + LOG("BUSY:" << level << ":" << obj << ":" << obj->className() ); + if( level > BUSY_NONE ) { + if( mBusyLevels.contains( obj ) && mBusyLevels[ obj ] == level ) return; + if( !mBusyLevels.contains( obj )) { + connect( obj, SIGNAL( destroyed( QObject* )), this, SLOT( objectDestroyed( QObject* ))); + } + mBusyLevels[ obj ] = level; + } else { + mBusyLevels.remove( obj ); + disconnect( obj, SIGNAL( destroyed( QObject* )), this, SLOT( objectDestroyed( QObject* ))); + } + mDelayedBusyLevelTimer.start( 0, true ); +} + +void BusyLevelManager::objectDestroyed( QObject* obj ) { + LOG("DESTROYED:" << obj ); + mBusyLevels.remove( obj ); + mDelayedBusyLevelTimer.start( 0, true ); +} + +void BusyLevelManager::delayedBusyLevelChanged() { + BusyLevel newLevel = BUSY_NONE; + for( QMap< QObject*, BusyLevel >::ConstIterator it = mBusyLevels.begin(); + it != mBusyLevels.end(); + ++it ) { + newLevel = QMAX( newLevel, *it ); + } + + if( newLevel != mCurrentBusyLevel ) { + LOG("CHANGED BUSY:" << newLevel); + mCurrentBusyLevel = newLevel; + emit busyLevelChanged( newLevel ); + } +} + +BusyLevel BusyLevelManager::busyLevel() const { + return mCurrentBusyLevel; +} + + +} // namespace diff --git a/src/gvcore/busylevelmanager.h b/src/gvcore/busylevelmanager.h new file mode 100644 index 0000000..21bee6d --- /dev/null +++ b/src/gvcore/busylevelmanager.h @@ -0,0 +1,113 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef BUSYLEVELMANAGER_H +#define BUSYLEVELMANAGER_H + +// Qt +#include +namespace Gwenview { + +// KDE +#include "libgwenview_export.h" + +/* + Busy level of the application. + Sorted by increasing priority. +*/ +enum BusyLevel { + BUSY_NONE, + BUSY_THUMBNAILS, + BUSY_PRELOADING, + BUSY_LOADING, + BUSY_SMOOTHING, + BUSY_PAINTING, + BUSY_CHECKING_NEW_IMAGE +}; + +class LIBGWENVIEW_EXPORT BusyLevelManager : public QObject { +Q_OBJECT +public: + static BusyLevelManager* instance(); + + /** + * Announces that the given object is busy. + */ + void setBusyLevel( QObject* obj, BusyLevel level ); + + /** + * Returns the busy level of the whole application (i.e. maximum). + */ + BusyLevel busyLevel() const; + +signals: + /** + * When emitted, operations that are less important than current level + * should be suspended until the level decreases to their level. + * E.g. when loading a picture thumbnail generation should get suspended. + */ + void busyLevelChanged( BusyLevel level ); + +private slots: + void delayedBusyLevelChanged(); + void objectDestroyed( QObject* obj ); + +private: + BusyLevelManager(); + QMap< QObject*, BusyLevel > mBusyLevels; + BusyLevel mCurrentBusyLevel; + QTimer mDelayedBusyLevelTimer; +}; + + +/** + Helper class. Constructor sets its busy level to the given level, + destructor resets the busy level to none. + */ +class BusyLevelHelper : public QObject { +Q_OBJECT +public: + BusyLevelHelper( BusyLevel level ); + ~BusyLevelHelper(); + void reset(); +}; + +inline +BusyLevelHelper::BusyLevelHelper( BusyLevel level ) +{ + BusyLevelManager::instance()->setBusyLevel( this, level ); +} + +inline +void BusyLevelHelper::reset() +{ + BusyLevelManager::instance()->setBusyLevel( this, BUSY_NONE ); +} + +inline +BusyLevelHelper::~BusyLevelHelper() +{ + reset(); +} + + +} // namespace +#endif + diff --git a/src/gvcore/cache.cpp b/src/gvcore/cache.cpp new file mode 100644 index 0000000..77b0211 --- /dev/null +++ b/src/gvcore/cache.cpp @@ -0,0 +1,402 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "cache.h" + +// Qt + +// KDE +#include +#include +#include +#include +#include +#include + +#include "cache.moc" + +namespace Gwenview { + +// Local + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +//#define DEBUG_CACHE + +const char CONFIG_CACHE_MAXSIZE[]="maxSize"; + + +struct ImageData : public KShared { + ImageData( const KURL& url, const QDateTime& _timestamp ) + : timestamp(_timestamp) + , age(0) + , fast_url( url.isLocalFile() && !KIO::probably_slow_mounted( url.path())) + , priority( false ) { + } + + void addFile( const QByteArray& file ); + void addImage( const ImageFrames& frames, const QCString& format ); + void addThumbnail( const QPixmap& thumbnail, QSize imagesize ); + long long cost() const; + int size() const; + QByteArray file; + ImageFrames frames; + QPixmap thumbnail; + QSize imagesize; + QCString format; + QDateTime timestamp; + mutable int age; + bool fast_url; + bool priority; + int fileSize() const; + int imageSize() const; + int thumbnailSize() const; + bool reduceSize(); + bool isEmpty() const; + + typedef KSharedPtr Ptr; +}; + +typedef QMap ImageMap; + +struct Cache::Private { + ImageMap mImages; + int mMaxSize; + int mThumbnailSize; + QValueList< KURL > mPriorityURLs; + + + /** + * This function tries to returns a valid ImageData for url and timestamp. + * If it can't find one, it will create a new one and return it. + */ + ImageData::Ptr getOrCreateImageData(const KURL& url, const QDateTime& timestamp) { + if (mImages.contains(url)) { + ImageData::Ptr data = mImages[url]; + if (data->timestamp == timestamp) return data; + } + + ImageData::Ptr data = new ImageData(url, timestamp); + mImages[url] = data; + if (mPriorityURLs.contains(url)) data->priority = true; + return data; + } +}; + + +Cache::Cache() +{ + d = new Private; + d->mMaxSize = DEFAULT_MAXSIZE; + // don't remember size for every thumbnail, but have one global and dump all if needed + d->mThumbnailSize = 0; +} + + +Cache::~Cache() { + d->mImages.clear(); + delete d; +} + + +static Cache* sCache; +static KStaticDeleter sCacheDeleter; + + +Cache* Cache::instance() { + if (!sCache) { + sCacheDeleter.setObject(sCache, new Cache()); + } + return sCache; +} + +// Priority URLs are used e.g. when prefetching for the slideshow - after an image is prefetched, +// the loader tries to put the image in the cache. When the slideshow advances, the next loader +// just gets the image from the cache. However, the prefetching may be useless if the image +// actually doesn't stay long enough in the cache, e.g. because of being too big for the cache. +// Marking an URL as a priority one will make sure it stays in the cache and that the cache +// will be even enlarged as necessary if needed. +void Cache::setPriorityURL( const KURL& url, bool set ) { + if( set ) { + d->mPriorityURLs.append( url ); + if( d->mImages.contains( url )) { + d->mImages[ url ]->priority = true; + } + } else { + d->mPriorityURLs.remove( url ); + if( d->mImages.contains( url )) { + d->mImages[ url ]->priority = false; + } + checkMaxSize(); + } +} + + +void Cache::addFile( const KURL& url, const QByteArray& file, const QDateTime& timestamp ) { + LOG(url.prettyURL()); + updateAge(); + d->getOrCreateImageData(url, timestamp)->addFile(file); + checkMaxSize(); +} + +void Cache::addImage( const KURL& url, const ImageFrames& frames, const QCString& format, const QDateTime& timestamp ) { + LOG(url.prettyURL()); + updateAge(); + d->getOrCreateImageData(url, timestamp)->addImage(frames, format); + checkMaxSize(); +} + +void Cache::addThumbnail( const KURL& url, const QPixmap& thumbnail, QSize imagesize, const QDateTime& timestamp ) { +// Thumbnails are many and often - things would age too quickly. Therefore +// when adding thumbnails updateAge() is called from the outside only once for all of them. +// updateAge(); + d->getOrCreateImageData(url, timestamp)->addThumbnail(thumbnail, imagesize); + checkMaxSize(); +} + +void Cache::invalidate( const KURL& url ) { + d->mImages.remove( url ); +} + +QDateTime Cache::timestamp( const KURL& url ) const { + LOG(url.prettyURL()); + if( d->mImages.contains( url )) return d->mImages[ url ]->timestamp; + return QDateTime(); +} + +QByteArray Cache::file( const KURL& url ) const { + LOG(url.prettyURL()); + if( d->mImages.contains( url )) { + const ImageData::Ptr data = d->mImages[ url ]; + if( data->file.isNull()) return QByteArray(); + data->age = 0; + return data->file; + } + return QByteArray(); +} + +void Cache::getFrames( const KURL& url, ImageFrames* frames, QCString* format ) const { + LOG(url.prettyURL()); + Q_ASSERT(frames); + Q_ASSERT(format); + frames->clear(); + *format = QCString(); + if( d->mImages.contains( url )) { + const ImageData::Ptr data = d->mImages[ url ]; + if( data->frames.isEmpty()) return; + *frames = data->frames; + *format = data->format; + data->age = 0; + } +} + +QPixmap Cache::thumbnail( const KURL& url, QSize& imagesize ) const { + if( d->mImages.contains( url )) { + const ImageData::Ptr data = d->mImages[ url ]; + if( data->thumbnail.isNull()) return QPixmap(); + imagesize = data->imagesize; +// data.age = 0; + return data->thumbnail; + } + return QPixmap(); +} + +void Cache::updateAge() { + for( ImageMap::Iterator it = d->mImages.begin(); + it != d->mImages.end(); + ++it ) { + (*it)->age++; + } +} + +void Cache::checkThumbnailSize( int size ) { + if( size != d->mThumbnailSize ) { + // simply remove all thumbnails, should happen rarely + for( ImageMap::Iterator it = d->mImages.begin(); + it != d->mImages.end(); + ) { + if( !(*it)->thumbnail.isNull()) { + ImageMap::Iterator it2 = it; + ++it; + d->mImages.remove( it2 ); + } else { + ++it; + } + } + d->mThumbnailSize = size; + } +} + +#ifdef DEBUG_CACHE +static KURL _cache_url; // hack only for debugging for item to show also its key +#endif + +void Cache::checkMaxSize() { + for(;;) { + int size = 0; + ImageMap::Iterator max; + long long max_cost = -1; +#ifdef DEBUG_CACHE + int with_file = 0; + int with_thumb = 0; + int with_image = 0; +#endif + for( ImageMap::Iterator it = d->mImages.begin(); + it != d->mImages.end(); + ++it ) { + size += (*it)->size(); +#ifdef DEBUG_CACHE + if( !(*it).file.isNull()) ++with_file; + if( !(*it).thumbnail.isNull()) ++with_thumb; + if( !(*it).frames.isEmpty()) ++with_image; +#endif + long long cost = (*it)->cost(); + if( cost > max_cost && ! (*it)->priority ) { + max_cost = cost; + max = it; + } + } + if( size <= d->mMaxSize || max_cost == -1 ) { +#if 0 +#ifdef DEBUG_CACHE + kdDebug() << "Cache: Statistics (" << d->mImages.size() << "/" << with_file << "/" + << with_thumb << "/" << with_image << ")" << endl; +#endif +#endif + break; + } +#ifdef DEBUG_CACHE + _cache_url = max.key(); +#endif + + if( !(*max)->reduceSize() || (*max)->isEmpty()) d->mImages.remove( max ); + } +} + +void Cache::readConfig(KConfig* config,const QString& group) { + KConfigGroupSaver saver( config, group ); + d->mMaxSize = config->readNumEntry( CONFIG_CACHE_MAXSIZE, d->mMaxSize ); + checkMaxSize(); +} + + +void ImageData::addFile( const QByteArray& f ) { + file = f; + file.detach(); // explicit sharing + age = 0; +} + +void ImageData::addImage( const ImageFrames& fs, const QCString& f ) { + frames = fs; + format = f; + age = 0; +} + +void ImageData::addThumbnail( const QPixmap& thumb, QSize imgsize ) { + thumbnail = thumb; + imagesize = imgsize; +// age = 0; +} + +int ImageData::size() const { + return QMAX( fileSize() + imageSize() + thumbnailSize(), 100 ); // some minimal size per item +} + +int ImageData::fileSize() const { + return !file.isNull() ? file.size() : 0; +} + +int ImageData::thumbnailSize() const { + return !thumbnail.isNull() ? thumbnail.height() * thumbnail.width() * thumbnail.depth() / 8 : 0; +} + +int ImageData::imageSize() const { + int ret = 0; + for( ImageFrames::ConstIterator it = frames.begin(); it != frames.end(); ++it ) { + ret += (*it).image.height() * (*it).image.width() * (*it).image.depth() / 8; + } + return ret; +} + +bool ImageData::reduceSize() { + if( !file.isNull() && fast_url && !frames.isEmpty()) { + file = QByteArray(); +#ifdef DEBUG_CACHE + kdDebug() << "Cache: Dumping fast file: " << _cache_url.prettyURL() << ":" << cost() << endl; +#endif + return true; + } + if( !thumbnail.isNull()) { +#ifdef DEBUG_CACHE + kdDebug() << "Cache: Dumping thumbnail: " << _cache_url.prettyURL() << ":" << cost() << endl; +#endif + thumbnail = QPixmap(); + return true; + } + if( !file.isNull() && !frames.isEmpty()) { + // possibly slow file to fetch - dump the image data unless the image + // is JPEG (which needs raw data anyway) or the raw data much larger than the image + if( format == "JPEG" || fileSize() < imageSize() / 10 ) { + frames.clear(); +#ifdef DEBUG_CACHE + kdDebug() << "Cache: Dumping images: " << _cache_url.prettyURL() << ":" << cost() << endl; +#endif + } else { + file = QByteArray(); +#ifdef DEBUG_CACHE + kdDebug() << "Cache: Dumping file: " << _cache_url.prettyURL() << ":" << cost() << endl; +#endif + } + return true; + } +#ifdef DEBUG_CACHE + kdDebug() << "Cache: Dumping completely: " << _cache_url.prettyURL() << ":" << cost() << endl; +#endif + return false; // reducing here would mean clearing everything +} + +bool ImageData::isEmpty() const { + return file.isNull() && frames.isEmpty() && thumbnail.isNull(); +} + +long long ImageData::cost() const { + long long s = size(); + if( fast_url && !file.isNull()) { + s *= ( format == "JPEG" ? 10 : 100 ); // heavy penalty for storing local files + } else if( !thumbnail.isNull()) { + s *= 10 * 10; // thumbnails are small, and try to get rid of them soon + } + static const int mod[] = { 50, 30, 20, 16, 12, 10 }; + if( age <= 5 ) { + return s * 10 / mod[ age ]; + } else { + return s * ( age - 5 ); + } +} + +} // namespace diff --git a/src/gvcore/cache.h b/src/gvcore/cache.h new file mode 100644 index 0000000..bf81b91 --- /dev/null +++ b/src/gvcore/cache.h @@ -0,0 +1,67 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef CACHE_H +#define CACHE_H + +// Qt +#include +#include +#include +#include +#include +#include + +// KDE +#include + +// Local +#include "imageframe.h" +#include "libgwenview_export.h" +class KConfig; + +namespace Gwenview { +class LIBGWENVIEW_EXPORT Cache : public QObject { +Q_OBJECT +public: + static Cache* instance(); + ~Cache(); + void addImage( const KURL& url, const ImageFrames& frames, const QCString& format, const QDateTime& timestamp ); + void addFile( const KURL& url, const QByteArray& file, const QDateTime& timestamp ); + void addThumbnail( const KURL& url, const QPixmap& thumbnail, QSize imagesize, const QDateTime& timestamp ); + QDateTime timestamp( const KURL& url ) const; + QByteArray file( const KURL& url ) const; + void getFrames( const KURL& url, ImageFrames* frames, QCString* format ) const; + QPixmap thumbnail( const KURL& url, QSize& imagesize ) const; + void setPriorityURL( const KURL& url, bool set ); + void invalidate( const KURL& url ); + void checkThumbnailSize( int size ); + void readConfig(KConfig*,const QString& group); + void updateAge(); + enum { DEFAULT_MAXSIZE = 16 * 1024 * 1024 }; // 16MiB +private: + Cache(); + void checkMaxSize(); + class Private; + Private* d; +}; + +} // namespace +#endif diff --git a/src/gvcore/captionformatter.cpp b/src/gvcore/captionformatter.cpp new file mode 100644 index 0000000..4bfac6b --- /dev/null +++ b/src/gvcore/captionformatter.cpp @@ -0,0 +1,57 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2005 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "captionformatter.h" + +// KDE +#include + + +namespace Gwenview { + + +QString CaptionFormatter::format(const QString& format) { + QString comment=mComment; + if (comment.isNull()) { + comment=i18n("(No comment)"); + } + + QString resolution; + if (mImageSize.isValid()) { + resolution = QString( "%1x%2" ).arg( mImageSize.width()).arg( mImageSize.height()); + } + + QString str=format; + str.replace("%f", mFileName); + str.replace("%p", mPath); + str.replace("%c", comment); + str.replace("%r", resolution); + str.replace("%n", QString::number(mPosition)); + str.replace("%N", QString::number(mCount)); + str.replace("%a", mAperture); + str.replace("%t", mExposureTime); + str.replace("%i", mIso); + str.replace("%l", mFocalLength); + + return str; +} + + +} // namespace diff --git a/src/gvcore/captionformatter.h b/src/gvcore/captionformatter.h new file mode 100644 index 0000000..edce26a --- /dev/null +++ b/src/gvcore/captionformatter.h @@ -0,0 +1,57 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2005 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef CAPTIONFORMATTER_H +#define CAPTIONFORMATTER_H + +// Qt +#include +#include + +// Local +#include "libgwenview_export.h" + +namespace Gwenview { + + +/** + * A class to format image captions. Used for example in fullscreen mode. + * All attributes of the class are public because it's just a "record" with a + * format() function. + */ +class LIBGWENVIEW_EXPORT CaptionFormatter { +public: + QString mPath; + QString mFileName; + QString mComment; + QString mAperture; + QString mFocalLength; + QString mExposureTime; + QString mIso; + + QSize mImageSize; + int mPosition; + int mCount; + QString format(const QString& format); +}; + +} // namespace + +#endif /* CAPTIONFORMATTER_H */ diff --git a/src/gvcore/clicklineedit.cpp b/src/gvcore/clicklineedit.cpp new file mode 100644 index 0000000..a1728a0 --- /dev/null +++ b/src/gvcore/clicklineedit.cpp @@ -0,0 +1,106 @@ +/* + This file is part of libkdepim. + Copyright (c) 2004 Daniel Molkentin + based on code by Cornelius Schumacher + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#include "clicklineedit.h" + +#include "qpainter.h" + +namespace Gwenview { + +ClickLineEdit::ClickLineEdit(QWidget *parent, const char* name ) : + KLineEdit( parent, name ) +{ + mDrawClickMsg = true; +} + + +///////////////////////////////////////////////////////////////////////////////////// +// PUBLIC +///////////////////////////////////////////////////////////////////////////////////// + +void ClickLineEdit::setClickMessage( const QString &msg ) +{ + mClickMessage = msg; + repaint(); +} + + +void ClickLineEdit::setText( const QString &txt ) +{ + mDrawClickMsg = txt.isEmpty(); + repaint(); + KLineEdit::setText( txt ); +} + + +///////////////////////////////////////////////////////////////////////////////////// +// PROTECTED +///////////////////////////////////////////////////////////////////////////////////// + +//#include +void ClickLineEdit::drawContents( QPainter *p ) +{ + KLineEdit::drawContents( p ); + + if ( mDrawClickMsg == true && !hasFocus() ) { + QPen tmp = p->pen(); + p->setPen( palette().color( QPalette::Disabled, QColorGroup::Text ) ); + QRect cr = contentsRect(); + + //p->drawPixmap( 3, 3, SmallIcon("filter") ); + + // Add two pixel margin on the left side + cr.rLeft() += 3; + p->drawText( cr, AlignAuto | AlignVCenter, mClickMessage ); + p->setPen( tmp ); + } +} + +void ClickLineEdit::dropEvent( QDropEvent *ev ) +{ + mDrawClickMsg = false; + KLineEdit::dropEvent( ev ); +} + + +void ClickLineEdit::focusInEvent( QFocusEvent *ev ) +{ + if ( mDrawClickMsg == true ) { + mDrawClickMsg = false; + repaint(); + } + QLineEdit::focusInEvent( ev ); +} + + +void ClickLineEdit::focusOutEvent( QFocusEvent *ev ) +{ + if ( text().isEmpty() ) { + mDrawClickMsg = true; + repaint(); + } + QLineEdit::focusOutEvent( ev ); +} +} // namespace + +#include "clicklineedit.moc" + diff --git a/src/gvcore/clicklineedit.h b/src/gvcore/clicklineedit.h new file mode 100644 index 0000000..05624eb --- /dev/null +++ b/src/gvcore/clicklineedit.h @@ -0,0 +1,63 @@ +/* + This file is part of libkdepim. + Copyright (c) 2004 Daniel Molkentin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef CLICKLINEEDIT_H +#define CLICKLINEEDIT_H + +#include + +namespace Gwenview { + +/** + This class provides a KLineEdit which contains a greyed-out hinting + text as long as the user didn't enter any text + + @short LineEdit with customizable "Click here" text + @author Daniel Molkentin +*/ +class ClickLineEdit : public KLineEdit +{ + Q_OBJECT + Q_PROPERTY( QString clickMessage READ clickMessage WRITE setClickMessage ) + public: + ClickLineEdit(QWidget *parent, const char* name = 0 ); + + void setClickMessage( const QString &msg ); + QString clickMessage() const { return mClickMessage; } + + virtual void setText( const QString& txt ); + + protected: + virtual void drawContents( QPainter *p ); + virtual void dropEvent( QDropEvent *ev ); + virtual void focusInEvent( QFocusEvent *ev ); + virtual void focusOutEvent( QFocusEvent *ev ); + + private: + QString mClickMessage; + bool mDrawClickMsg; + +}; + +} + +#endif // CLICKLINEEDIT_H + + diff --git a/src/gvcore/cursortracker.cpp b/src/gvcore/cursortracker.cpp new file mode 100644 index 0000000..cc7ff89 --- /dev/null +++ b/src/gvcore/cursortracker.cpp @@ -0,0 +1,86 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "cursortracker.h" + +// Qt +#include +#include + +namespace Gwenview { + +CursorTracker::CursorTracker(const QString& txt, QWidget* reference) +: QLabel(txt, 0, "", WX11BypassWM) { + reference->setMouseTracking(true); + reference->installEventFilter(this); +} + + +/** + * Overload to make sure the widget size is correct + */ +void CursorTracker::setText(const QString& txt) { + QLabel::setText(txt); + adjustSize(); +} + + +bool CursorTracker::eventFilter(QObject* object, QEvent* _event) { + QWidget* widget=static_cast(object); + + switch (_event->type()) { + case QEvent::MouseMove: { + QMouseEvent* event=static_cast(_event); + if (widget->rect().contains(event->pos()) || (event->stateAfter() & LeftButton)) { + show(); + move(event->globalPos().x() + 15, event->globalPos().y() + 15); + } else { + hide(); + } + break; + } + + case QEvent::MouseButtonRelease: { + QMouseEvent* event=static_cast(_event); + if ( !widget->rect().contains(event->pos()) ) { + hide(); + } + break; + } + + default: + break; + } + + return false; +} + + +TipTracker::TipTracker(const QString& txt, QWidget* reference) +: CursorTracker(txt, reference) { + setPalette(QToolTip::palette()); + setFrameStyle(QFrame::Plain | QFrame::Box); + setLineWidth(1); + setAlignment(AlignAuto | AlignTop); +} + + +} // namespace diff --git a/src/gvcore/cursortracker.h b/src/gvcore/cursortracker.h new file mode 100644 index 0000000..1dc4003 --- /dev/null +++ b/src/gvcore/cursortracker.h @@ -0,0 +1,56 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef CURSORTRACKER_H +#define CURSORTRACKER_H + +// Qt +#include + +namespace Gwenview { + +/** + * This class implements a decoration-less window which will follow the cursor + * when it's over a specified widget. + */ +class CursorTracker : public QLabel { +public: + CursorTracker(const QString& txt, QWidget* reference); + + void setText(const QString& txt); + +protected: + bool eventFilter(QObject*, QEvent*); +}; + + +/** + * A specialized CursorTracker class, which looks like a tool tip. + */ +class TipTracker : public CursorTracker { +public: + TipTracker(const QString& txt, QWidget* reference); +}; + + +} // namespace + +#endif /* CURSORTRACKER_H */ diff --git a/src/gvcore/deletedialog.cpp b/src/gvcore/deletedialog.cpp new file mode 100644 index 0000000..19c34ba --- /dev/null +++ b/src/gvcore/deletedialog.cpp @@ -0,0 +1,133 @@ +/*************************************************************************** + begin : Tue Aug 31 21:59:58 EST 2004 + copyright : (C) 2004 by Michael Pyne + (C) 2006 by Ian Monroe + (C) 2006 by Aurelien Gateau +***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fileoperationconfig.h" +#include "deletedialog.h" +#include "deletedialogbase.h" + +namespace Gwenview { + +DeleteDialog::DeleteDialog(QWidget *parent, const char *name) : + KDialogBase(Swallow, WStyle_DialogBorder, parent, name, + true /* modal */, i18n("About to delete selected files"), + Ok | Cancel, Cancel /* Default */, true /* separator */), + m_trashGuiItem(i18n("&Send to Trash"), "trashcan_full") +{ + m_widget = new DeleteDialogBase(this, "delete_dialog_widget"); + setMainWidget(m_widget); + + m_widget->setMinimumSize(400, 300); + + actionButton(Ok)->setFocus(); + + bool deleteInstead = ! FileOperationConfig::deleteToTrash(); + m_widget->ddShouldDelete->setChecked(deleteInstead); + + connect(m_widget->ddShouldDelete, SIGNAL(toggled(bool)), SLOT(updateUI())); +} + +void DeleteDialog::setURLList(const KURL::List &files) +{ + m_widget->ddFileList->clear(); + for( KURL::List::ConstIterator it = files.begin(); it != files.end(); it++) { + m_widget->ddFileList->insertItem( (*it).pathOrURL() ); + } + m_widget->ddNumFiles->setText(i18n("1 item selected.", "%n items selected.", files.count())); + updateUI(); +} + +void DeleteDialog::accept() +{ + FileOperationConfig::setDeleteToTrash( ! shouldDelete() ); + FileOperationConfig::writeConfig(); + + KDialogBase::accept(); +} + + +void DeleteDialog::updateUI() +{ + QString msg, iconName; + + int fileCount = m_widget->ddFileList->count(); + bool reallyDelete = m_widget->ddShouldDelete->isChecked(); + + if(reallyDelete) { + msg = i18n( + "This item will be permanently deleted from your hard disk.", + "These items will be permanently deleted from your hard disk.", + fileCount); + iconName = "messagebox_warning"; + } + else { + msg = i18n( + "This item will be moved to the trash bin.", + "These items will be moved to the trash bin.", + fileCount); + iconName = "trashcan_full"; + } + QPixmap icon = KGlobal::iconLoader()->loadIcon(iconName, KIcon::NoGroup, KIcon::SizeMedium); + + m_widget->ddDeleteText->setText(msg); + m_widget->ddWarningIcon->setPixmap(icon); + + setButtonGuiItem(Ok, reallyDelete ? KStdGuiItem::del() : m_trashGuiItem); + adjustSize(); +} + + +bool DeleteDialog::shouldDelete() const { + return m_widget->ddShouldDelete->isChecked(); +} + + +QSize DeleteDialog::sizeHint() const { + m_widget->adjustSize(); + QSize hint = m_widget->minimumSize(); + hint = calculateSize(hint.width(), hint.height()); + + // For some reason calculateSize does not return a correct height. As I'm + // fed up fighting with it, let's just add a few more pixels. + hint.rheight() += 50; + return hint; +} + + + +} // namespace + +#include "deletedialog.moc" + +// vim: set et ts=4 sw=4: diff --git a/src/gvcore/deletedialog.h b/src/gvcore/deletedialog.h new file mode 100644 index 0000000..0340e09 --- /dev/null +++ b/src/gvcore/deletedialog.h @@ -0,0 +1,55 @@ +/*************************************************************************** + begin : Tue Aug 31 21:54:20 EST 2004 + copyright : (C) 2004 by Michael Pyne + (C) 2006 by Ian Monroe + (C) 2006 by Aurelien Gateau +***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _DELETEDIALOG_H +#define _DELETEDIALOG_H + + +#include + +class DeleteDialogBase; +class KGuiItem; + +namespace Gwenview { + +class DeleteDialog : public KDialogBase +{ + Q_OBJECT + +public: + DeleteDialog(QWidget *parent, const char *name = "delete_dialog"); + + void setURLList(const KURL::List &files); + bool shouldDelete() const; + + QSize sizeHint() const; + +protected slots: + virtual void accept(); + +private slots: + void updateUI(); + +private: + DeleteDialogBase *m_widget; + KGuiItem m_trashGuiItem; +}; + +} // namespace + +#endif + +// vim: set et ts=4 sw=4: diff --git a/src/gvcore/deletedialogbase.ui b/src/gvcore/deletedialogbase.ui new file mode 100644 index 0000000..dd338ea --- /dev/null +++ b/src/gvcore/deletedialogbase.ui @@ -0,0 +1,111 @@ + +DeleteDialogBase + + + DeleteDialogBase + + + + 0 + 0 + 542 + 374 + + + + + unnamed + + + 0 + + + + layout3 + + + + unnamed + + + + ddWarningIcon + + + + 4 + 4 + 0 + 0 + + + + Icon Placeholder, not in GUI + + + + + ddDeleteText + + + + 0 + 60 + + + + Deletion method placeholder, not in GUI + + + WordBreak|AlignCenter + + + + + + + ddFileList + + + NoFocus + + + NoSelection + + + + + ddNumFiles + + + Placeholder for number of files, not in GUI + + + AlignVCenter|AlignRight + + + + + ddShouldDelete + + + &Delete items instead of moving them to the trash + + + If checked, items will be permanently removed instead of being placed in the trash bin + + + <qt><p>If this box is checked, items will be <b>permanently removed</b> instead of being placed in the trash bin.</p> + +<p><em>Use this option with caution</em>: Most filesystems are unable to reliably undelete deleted files.</p></qt> + + + + + + + + + klistbox.h + + diff --git a/src/gvcore/document.cpp b/src/gvcore/document.cpp new file mode 100644 index 0000000..058efe2 --- /dev/null +++ b/src/gvcore/document.cpp @@ -0,0 +1,618 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2006 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include // For S_ISDIR + +// Qt +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "archive.h" +#include "busylevelmanager.h" +#include "cache.h" +#include "documentloadingimpl.h" +#include "documentimpl.h" +#include "imagesavedialog.h" +#include "imageutils/imageutils.h" +#include "jpegformattype.h" +#include "pngformattype.h" +#include "mngformattype.h" +#include "printdialog.h" +#include "qxcfi.h" +#include "xpm.h" +#include "xcursor.h" + +#include "document.moc" +namespace Gwenview { + + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +const char* CONFIG_SAVE_AUTOMATICALLY="save automatically"; + + +/** + * Returns a widget suitable to use as a dialog parent + */ +static QWidget* dialogParentWidget() { + return KApplication::kApplication()->mainWidget(); +} + +//------------------------------------------------------------------- +// +// DocumentPrivate +// +//------------------------------------------------------------------- +class DocumentPrivate { +public: + KURL mURL; + bool mModified; + QImage mImage; + QString mMimeType; + QCString mImageFormat; + DocumentImpl* mImpl; + QGuardedPtr mStatJob; + int mFileSize; +}; + + +//------------------------------------------------------------------- +// +// Document +// +//------------------------------------------------------------------- +Document::Document(QObject* parent) +: QObject(parent) { + d=new DocumentPrivate; + d->mModified=false; + d->mImpl=new DocumentEmptyImpl(this); + d->mStatJob=0L; + d->mFileSize=-1; + + // Register formats here to make sure they are always enabled + KImageIO::registerFormats(); + XCFImageFormat::registerFormat(); + + // First load Qt's plugins, so that Gwenview's decoders that + // override some of them are installed later and thus come first. + QImageIO::inputFormats(); + { + static Gwenview::JPEGFormatType sJPEGFormatType; + static Gwenview::PNGFormatType sPNGFormatType; + static Gwenview::XPM sXPM; + static Gwenview::MNG sMNG; + static Gwenview::XCursorFormatType sXCursorFormatType; + } + + connect( this, SIGNAL( loading()), + this, SLOT( slotLoading())); + connect( this, SIGNAL( loaded(const KURL&)), + this, SLOT( slotLoaded())); +} + + +Document::~Document() { + delete d->mImpl; + delete d; +} + + +//--------------------------------------------------------------------- +// +// Properties +// +//--------------------------------------------------------------------- +QString Document::mimeType() const { + return d->mMimeType; +} + +void Document::setMimeType(const QString& mimeType) { + d->mMimeType = mimeType; +} + +MimeTypeUtils::Kind Document::urlKind() const { + return d->mImpl->urlKind(); +} + + +KURL Document::url() const { + return d->mURL; +} + + +void Document::setURL(const KURL& paramURL) { + if (paramURL==url()) return; + // Make a copy, we might have to fix the protocol + KURL localURL(paramURL); + LOG("url: " << paramURL.prettyURL()); + + // Be sure we are not waiting for another stat result + if (!d->mStatJob.isNull()) { + d->mStatJob->kill(); + } + BusyLevelManager::instance()->setBusyLevel(this, BUSY_NONE); + + // Ask to save if necessary. + saveBeforeClosing(); + + if (localURL.isEmpty()) { + reset(); + return; + } + + // Set high busy level, so that operations like smoothing are suspended. + // Otherwise the stat() below done using KIO can take quite long. + BusyLevelManager::instance()->setBusyLevel( this, BUSY_CHECKING_NEW_IMAGE ); + + + // Fix wrong protocol + if (Archive::protocolIsArchive(localURL.protocol())) { + QFileInfo info(localURL.path()); + if (info.exists()) { + localURL.setProtocol("file"); + } + } + + d->mURL = localURL; // this may be fixed after stat() is complete, but set at least something + d->mStatJob = KIO::stat( localURL, !localURL.isLocalFile() ); + d->mStatJob->setWindow(KApplication::kApplication()->mainWidget()); + connect( d->mStatJob, SIGNAL( result (KIO::Job *) ), + this, SLOT( slotStatResult (KIO::Job *) ) ); +} + + +void Document::slotStatResult(KIO::Job* job) { + LOG(""); + Q_ASSERT(d->mStatJob==job); + if (d->mStatJob!=job) { + kdWarning() << k_funcinfo << "We did not get the right job!\n"; + return; + } + BusyLevelManager::instance()->setBusyLevel( this, BUSY_NONE ); + if (d->mStatJob->error()) return; + + bool isDir=false; + KIO::UDSEntry entry = d->mStatJob->statResult(); + d->mURL=d->mStatJob->url(); + + KIO::UDSEntry::ConstIterator it; + for(it=entry.begin();it!=entry.end();++it) { + if ((*it).m_uds==KIO::UDS_FILE_TYPE) { + isDir=S_ISDIR( (*it).m_long ); + break; + } + } + + if (isDir) { + d->mURL.adjustPath( +1 ); // add trailing / + reset(); + return; + } + + load(); +} + + +void Document::setDirURL(const KURL& paramURL) { + saveBeforeClosing(); + d->mURL=paramURL; + d->mURL.adjustPath( +1 ); // add trailing / + reset(); +} + + +const QImage& Document::image() const { + return d->mImage; +} + +void Document::setImage(QImage img) { + bool sizechange = d->mImage.size() != img.size(); + d->mImage = img; + if( sizechange ) emit sizeUpdated(); +} + + +KURL Document::dirURL() const { + if (filename().isEmpty()) { + return d->mURL; + } else { + KURL url=d->mURL.upURL(); + url.adjustPath(1); + return url; + } +} + +QString Document::filename() const { + return d->mURL.filename(false); +} + +const QCString& Document::imageFormat() const { + return d->mImageFormat; +} + +void Document::setImageFormat(const QCString& format) { + d->mImageFormat=format; +} + +void Document::setFileSize(int size) { + d->mFileSize=size; +} + +QString Document::comment() const { + return d->mImpl->comment(); +} + +QString Document::aperture() const { + return d->mImpl->aperture(); +} + +QString Document::exposureTime() const { + return d->mImpl->exposureTime(); +} + +QString Document::iso() const { + return d->mImpl->iso(); +} + +QString Document::focalLength() const { + return d->mImpl->focalLength(); +} + +void Document::setComment(const QString& comment) { + d->mImpl->setComment(comment); + d->mModified=true; + emit modified(); +} + +Document::CommentState Document::commentState() const { + return d->mImpl->commentState(); +} + +/** + * Returns the duration of the document in seconds, or 0 if there is no + * duration + */ +int Document::duration() const { + return d->mImpl->duration(); +} + +int Document::fileSize() const { + return d->mFileSize; +} + +bool Document::canBeSaved() const { + return d->mImpl->canBeSaved(); +} + +bool Document::isModified() const { + return d->mModified; +} + +void Document::slotLoading() { + BusyLevelManager::instance()->setBusyLevel( this, BUSY_LOADING ); +} + +void Document::slotLoaded() { + BusyLevelManager::instance()->setBusyLevel( this, BUSY_NONE ); +} + +//--------------------------------------------------------------------- +// +// Operations +// +//--------------------------------------------------------------------- +void Document::reload() { + Cache::instance()->invalidate( url()); + load(); + emit reloaded(url()); +} + + +void Document::print(KPrinter *pPrinter) { + QPainter printPainter; + printPainter.begin(pPrinter); + doPaint(pPrinter, &printPainter); + printPainter.end(); +} + + +void Document::doPaint(KPrinter *printer, QPainter *painter) { + // will contain the final image to print + QImage image = d->mImage; + image.detach(); + + // We use a QPaintDeviceMetrics to know the actual page size in pixel, + // this gives the real painting area + QPaintDeviceMetrics pdMetrics(painter->device()); + const int margin = pdMetrics.logicalDpiY() / 2; // half-inch margin + + painter->setFont( KGlobalSettings::generalFont() ); + QFontMetrics fMetrics = painter->fontMetrics(); + + int x = 0; + int y = 0; + int pdWidth = pdMetrics.width(); + int pdHeight = pdMetrics.height(); + + QString t = "true"; + QString f = "false"; + + int alignment = (printer->option("app-gwenview-position").isEmpty() ? + Qt::AlignCenter : printer->option("app-gwenview-position").toInt()); + + // Compute filename offset + int filenameOffset = 0; + bool printFilename = printer->option( "app-gwenview-printFilename" ) != f; + if ( printFilename ) { + filenameOffset = fMetrics.lineSpacing() + 14; + pdHeight -= filenameOffset; // filename goes into one line! + } + + // Compute comment offset + int commentOffset = 0; + bool printComment = printer->option( "app-gwenview-printComment" ) != f; + if ( commentOffset ) { + commentOffset = fMetrics.lineSpacing() + 14;// #### TODO check if it's correct + pdHeight -= commentOffset; // #### TODO check if it's correct + } + if (commentOffset || printFilename) { + pdHeight -= margin; + } + + // Apply scaling + int scaling = printer->option( "app-gwenview-scale" ).toInt(); + + QSize size = image.size(); + if (scaling==GV_FITTOPAGE /* Fit to page */) { + bool enlargeToFit = printer->option( "app-gwenview-enlargeToFit" ) != f; + if ((image.width() > pdWidth || image.height() > pdHeight) || enlargeToFit) { + size.scale( pdWidth, pdHeight, QSize::ScaleMin ); + } + } else { + if (scaling==GV_SCALE /* Scale To */) { + int unit = (printer->option("app-gwenview-scaleUnit").isEmpty() ? + GV_INCHES : printer->option("app-gwenview-scaleUnit").toInt()); + double inches = 1; + if (unit == GV_MILLIMETERS) { + inches = 1/25.4; + } else if (unit == GV_CENTIMETERS) { + inches = 1/2.54; + } + double wImg = (printer->option("app-gwenview-scaleWidth").isEmpty() ? + 1 : printer->option("app-gwenview-scaleWidth").toDouble()) * inches; + double hImg = (printer->option("app-gwenview-scaleHeight").isEmpty() ? + 1 : printer->option("app-gwenview-scaleHeight").toDouble()) * inches; + size.setWidth( int(wImg * printer->resolution()) ); + size.setHeight( int(hImg * printer->resolution()) ); + } else { + /* GV_NOSCALE: no scaling */ + // try to get the density info so that we can print using original size + // known if it is am image from scanner for instance + const float INCHESPERMETER = (100. / 2.54); + if (image.dotsPerMeterX()) + { + double wImg = double(size.width()) / double(image.dotsPerMeterX()) * INCHESPERMETER; + size.setWidth( int(wImg *printer->resolution()) ); + } + if (image.dotsPerMeterY()) + { + double hImg = double(size.height()) / double(image.dotsPerMeterY()) * INCHESPERMETER; + size.setHeight( int(hImg *printer->resolution()) ); + } + } + + if (size.width() > pdWidth || size.height() > pdHeight) { + int resp = KMessageBox::warningYesNoCancel(dialogParentWidget(), + i18n("The image will not fit on the page, what do you want to do?"), + QString::null,KStdGuiItem::cont(), + i18n("Shrink") ); + + if (resp==KMessageBox::Cancel) { + printer->abort(); + return; + } else if (resp == KMessageBox::No) { // Shrink + size.scale(pdWidth, pdHeight, QSize::ScaleMin); + } + } + } + + // Compute x and y + if ( alignment & Qt::AlignHCenter ) + x = (pdWidth - size.width())/2; + else if ( alignment & Qt::AlignLeft ) + x = 0; + else if ( alignment & Qt::AlignRight ) + x = pdWidth - size.width(); + + if ( alignment & Qt::AlignVCenter ) + y = (pdHeight - size.height())/2; + else if ( alignment & Qt::AlignTop ) + y = 0; + else if ( alignment & Qt::AlignBottom ) + y = pdHeight - size.height(); + + // Draw, the image will be scaled to fit the given area if necessary + painter->drawImage( QRect( x, y, size.width(), size.height()), image ); + + if ( printFilename ) { + QString fname = KStringHandler::cPixelSqueeze( filename(), fMetrics, pdWidth ); + if ( !fname.isEmpty() ) { + int fw = fMetrics.width( fname ); + int x = (pdWidth - fw)/2; + int y = pdMetrics.height() - filenameOffset/2 -commentOffset/2 - margin; + painter->drawText( x, y, fname ); + } + } + if ( printComment ) { + QString comm = comment(); + if ( !comm.isEmpty() ) { + int fw = fMetrics.width( comm ); + int x = (pdWidth - fw)/2; + int y = pdMetrics.height() - commentOffset/2 - margin; + painter->drawText( x, y, comm ); + } + } +} + + +void Document::transform(ImageUtils::Orientation orientation) { + d->mImpl->transform(orientation); + d->mModified=true; + emit modified(); +} + + +void Document::save() { + QString msg=saveInternal(url(), d->mImageFormat); + if (!msg.isNull()) { + KMessageBox::error(dialogParentWidget(), msg); + // If it can't be saved we leave it as modified, because user + // could choose to save it to another path with saveAs + } +} + + +void Document::saveAs() { + KURL saveURL; + + ImageSaveDialog dialog(saveURL, d->mImageFormat, dialogParentWidget()); + dialog.setSelection(url().fileName()); + if (!dialog.exec()) return; + + QString msg=saveInternal(saveURL, dialog.imageFormat() ); + if (!msg.isNull()) { + // If it can't be saved we leave it as modified, because user + // could choose a wrong readonly path from dialog and retry to + KMessageBox::error(dialogParentWidget(), msg); + } +} + +void Document::saveBeforeClosing() { + if (!d->mModified) return; + + QString msg=i18n("The image %1 has been modified, do you want to save the changes?") + .arg(url().prettyURL()); + + int result=KMessageBox::questionYesNo(dialogParentWidget(), msg, QString::null, + KStdGuiItem::save(), KStdGuiItem::discard(), CONFIG_SAVE_AUTOMATICALLY); + + if (result == KMessageBox::Yes) { + saveInternal(url(), d->mImageFormat); + // If it can't be saved it's useless to leave it as modified + // since user is closing this image and changing to another one + d->mModified=false; + //FIXME it should be nice to tell the user it failed + } else { + d->mModified=false; + } +} + + +//--------------------------------------------------------------------- +// +// Private stuff +// +//--------------------------------------------------------------------- +void Document::switchToImpl(DocumentImpl* impl) { + // There should always be an implementation defined + Q_ASSERT(d->mImpl); + Q_ASSERT(impl); + delete d->mImpl; + d->mImpl=impl; + + connect(d->mImpl, SIGNAL(finished(bool)), + this, SLOT(slotFinished(bool)) ); + connect(d->mImpl, SIGNAL(sizeUpdated()), + this, SIGNAL(sizeUpdated()) ); + connect(d->mImpl, SIGNAL(rectUpdated(const QRect&)), + this, SIGNAL(rectUpdated(const QRect&)) ); + d->mImpl->init(); +} + + +void Document::load() { + KURL pixURL=url(); + Q_ASSERT(!pixURL.isEmpty()); + LOG("url: " << pixURL.prettyURL()); + + // DocumentLoadingImpl might emit "finished()" in its "init()" method, so + // make sure we emit "loading()" before switching + emit loading(); + switchToImpl(new DocumentLoadingImpl(this)); +} + + +void Document::slotFinished(bool success) { + LOG(""); + if (success) { + emit loaded(d->mURL); + } else { + // FIXME: Emit a failed signal instead + emit loaded(d->mURL); + } +} + + +QString Document::saveInternal(const KURL& url, const QCString& format) { + QString msg=d->mImpl->save(url, format); + + if (msg.isNull()) { + emit saved(url); + d->mModified=false; + return QString::null; + } + + LOG("Save failed: " << msg); + return QString("%1
") + .arg(i18n("Could not save the image to %1.").arg(url.prettyURL())) + + msg + "
"; +} + + +void Document::reset() { + switchToImpl(new DocumentEmptyImpl(this)); + emit loaded(d->mURL); +} + +} // namespace diff --git a/src/gvcore/document.h b/src/gvcore/document.h new file mode 100644 index 0000000..98b14ca --- /dev/null +++ b/src/gvcore/document.h @@ -0,0 +1,194 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2006 Aurelien Gateau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef DOCUMENT_H +#define DOCUMENT_H + +// Qt +#include +#include +#include + +// KDE +#include +#include + +// Local +#include "imageutils/orientation.h" +#include "mimetypeutils.h" +#include "libgwenview_export.h" +namespace KIO { class Job; } + +namespace Gwenview { +class DocumentPrivate; +class DocumentImpl; + +/** + * The application document. + * It knows what the current url is and will emit signals when + * loading/loaded/modified... + * + * The ordering of loading() and loaded() signals is: + * - setURL() is called + * - URL is stated + * - loading() is emitted (may be skipped if no loading is needed, e.g. wrong URL) + * - image is being loaded + * - loaded() is emitted + */ +class LIBGWENVIEW_EXPORT Document : public QObject { +Q_OBJECT +public: + enum CommentState { NONE=0, READ_ONLY=1, WRITABLE=2 }; + + Document(QObject*); + ~Document(); + + // Properties + const QImage& image() const; + KURL url() const; + KURL dirURL() const; + QString filename() const; + const QCString& imageFormat() const; + int fileSize() const; + QString mimeType() const; + MimeTypeUtils::Kind urlKind() const; + bool isModified() const; + + /** + * Returns true if Gwenview knows how to save such an image + */ + bool canBeSaved() const; + + // Convenience methods + bool isNull() const { return image().isNull(); } + int width() const { return image().width(); } + int height() const { return image().height(); } + + Document::CommentState commentState() const; + QString comment() const; + void setComment(const QString&); + QString aperture() const; + QString exposureTime() const; + QString iso() const; + QString focalLength() const; + + int duration() const; + +public slots: + void setURL(const KURL&); + void setDirURL(const KURL&); + void reload(); + + /** + * Save to the current file. + */ + void save(); + void saveAs(); + + /** print the selected file */ + void print(KPrinter *pPrinter); + + /** + * If the image has been modified, prompt the user to save the changes. + */ + void saveBeforeClosing(); + + // "Image manipulation" + void transform(ImageUtils::Orientation); + +signals: + /** + * Emitted when the class starts to load the image. + */ + void loading(); + + /** + * Emitted when the class has finished loading the image. + * Also emitted if the image could not be loaded. + */ + void loaded(const KURL& url); + + /** + * Emitted when the image has been modified. + */ + void modified(); + + /** + * Emitted when the image has been saved on disk. + */ + void saved(const KURL& url); + + /** + * Emitted when the image has been reloaded. + */ + void reloaded(const KURL& url); + + /** + * Emitted to show a part of the image must be refreshed + */ + void rectUpdated(const QRect& rect); + + /** + * Emitted when the size is known + */ + void sizeUpdated(); + + /** + * Emitted when something goes wrong, like when save fails + */ + void errorHappened(const QString& message); + +private slots: + void slotStatResult(KIO::Job*); + void slotFinished(bool success); + void slotLoading(); + void slotLoaded(); + +private: + friend class DocumentImpl; + friend class DocumentPrivate; + + DocumentPrivate* d; + + // These methods are used by DocumentImpl and derived + void switchToImpl(DocumentImpl*); + void setImage(QImage); + void setImageFormat(const QCString&); + void setMimeType(const QString&); + void setFileSize(int); + + void reset(); + void load(); + void doPaint(KPrinter *pPrinter, QPainter *p); + + /** + * The returned string is null if the image was successfully saved, + * otherwise it's the translated error message. + */ + QString saveInternal(const KURL& url, const QCString& format); + + Document(const Document&); + Document &operator=(const Document&); +}; + + +} // namespace +#endif + diff --git a/src/gvcore/documentanimatedloadedimpl.cpp b/src/gvcore/documentanimatedloadedimpl.cpp new file mode 100644 index 0000000..a6cabb1 --- /dev/null +++ b/src/gvcore/documentanimatedloadedimpl.cpp @@ -0,0 +1,97 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "documentanimatedloadedimpl.moc" + +// Qt +#include +#include + +// KDE +#include +#include +namespace Gwenview { + +// Local + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +class DocumentAnimatedLoadedImplPrivate { +public: + ImageFrames mFrames; + int mCurrentFrame; + QTimer mFrameTimer; +}; + + +DocumentAnimatedLoadedImpl::DocumentAnimatedLoadedImpl(Document* document, const ImageFrames& frames) +: DocumentLoadedImpl(document) { + LOG("" << mDocument->url().prettyURL() << ", frames: " << frames.count() ); + d=new DocumentAnimatedLoadedImplPrivate; + d->mFrames = frames; + d->mCurrentFrame = -1; + connect( &d->mFrameTimer, SIGNAL( timeout()), SLOT( nextFrame())); +} + +void DocumentAnimatedLoadedImpl::init() { + DocumentLoadedImpl::init(); + nextFrame(); +} + +void DocumentAnimatedLoadedImpl::nextFrame() { + ++d->mCurrentFrame; + if( d->mCurrentFrame == int( d->mFrames.count())) d->mCurrentFrame = 0; + d->mFrameTimer.start( QMAX( 10, d->mFrames[ d->mCurrentFrame ].delay )); +// NOTE! If this ever gets changed to already animate the picture while it's still +// loading, with MNG the frame delay gets announced only after the frame is ready. +// See ImageLoader::frameDone() . + LOG("" << d->mCurrentFrame ); + + setImage(d->mFrames[ d->mCurrentFrame ].image); + emitImageRectUpdated(); +} + +DocumentAnimatedLoadedImpl::~DocumentAnimatedLoadedImpl() { + delete d; +} + + +void DocumentAnimatedLoadedImpl::transform(ImageUtils::Orientation orientation) { + for( ImageFrames::Iterator it = d->mFrames.begin(); it != d->mFrames.end(); ++it ) { + (*it).image = ImageUtils::transform( (*it).image, orientation ); + } + setImage( d->mFrames[ d->mCurrentFrame ].image); + emitImageRectUpdated(); +} + + +QString DocumentAnimatedLoadedImpl::localSave(QFile* /*file*/, const QCString& /*format*/) const { + return i18n("Sorry, cannot save animated images."); +} + +} // namespace diff --git a/src/gvcore/documentanimatedloadedimpl.h b/src/gvcore/documentanimatedloadedimpl.h new file mode 100644 index 0000000..b9266b3 --- /dev/null +++ b/src/gvcore/documentanimatedloadedimpl.h @@ -0,0 +1,62 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef DOCUMENTANIMATEDIMPL_H +#define DOCUMENTANIMATEDIMPL_H + +// Qt +#include +#include + +// Local +#include "documentloadedimpl.h" +#include "imageutils/imageutils.h" +#include "imageframe.h" + +class QFile; +class QCString; + +namespace Gwenview { +class Document; + +class DocumentAnimatedLoadedImplPrivate; + +class DocumentAnimatedLoadedImpl : public DocumentLoadedImpl { +Q_OBJECT +public: + DocumentAnimatedLoadedImpl(Document* document, const ImageFrames& frames); + ~DocumentAnimatedLoadedImpl(); + void init(); + + void transform(ImageUtils::Orientation); + virtual bool canBeSaved() const { return false; } + +protected: + QString localSave(QFile*, const QCString& format) const; + +private slots: + void nextFrame(); +private: + DocumentAnimatedLoadedImplPrivate* d; +}; + +} // namespace +#endif /* DOCUMENTANIMATEDIMPL_H */ + diff --git a/src/gvcore/documentimpl.cpp b/src/gvcore/documentimpl.cpp new file mode 100644 index 0000000..3221229 --- /dev/null +++ b/src/gvcore/documentimpl.cpp @@ -0,0 +1,103 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// KDE +#include + +// Local +#include "document.h" +#include "documentimpl.moc" +namespace Gwenview { + +DocumentImpl::DocumentImpl(Document* document) +: mDocument(document) {} + +void DocumentImpl::init() {} + +DocumentImpl::~DocumentImpl() {} + +void DocumentImpl::switchToImpl(DocumentImpl* impl) { + mDocument->switchToImpl(impl); +} + +void DocumentImpl::setImage(QImage img) { + if (img.depth() == 1) { + // 1 bit depth images are difficult to scale. Let's convert to 8 bit + // depth. See bug #155518. + img = img.convertDepth(8); + } + mDocument->setImage(img); +} + +void DocumentImpl::emitImageRectUpdated() { + emit rectUpdated(mDocument->image().rect()); +} + +void DocumentImpl::setImageFormat(const QCString& format) { + mDocument->setImageFormat(format); +} + +void DocumentImpl::setMimeType(const QString& mimeType) { + mDocument->setMimeType(mimeType); +} + +void DocumentImpl::setFileSize(int size) const { + mDocument->setFileSize(size); +} + +QString DocumentImpl::aperture() const { + return QString::null; +} + +QString DocumentImpl::exposureTime() const { + return QString::null; +} + +QString DocumentImpl::iso() const { + return QString::null; +} + +QString DocumentImpl::focalLength() const { + return QString::null; +} + +QString DocumentImpl::comment() const { + return QString::null; +} + +Document::CommentState DocumentImpl::commentState() const { + return Document::NONE; +} + +void DocumentImpl::setComment(const QString&) { +} + +int DocumentImpl::duration() const { + return 0; +} + +void DocumentImpl::transform(ImageUtils::Orientation) { +} + +QString DocumentImpl::save(const KURL&, const QCString&) const { + return i18n("No document to save"); +} + +} // namespace diff --git a/src/gvcore/documentimpl.h b/src/gvcore/documentimpl.h new file mode 100644 index 0000000..d5ca875 --- /dev/null +++ b/src/gvcore/documentimpl.h @@ -0,0 +1,103 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef DOCUMENTIMPL_H +#define DOCUMENTIMPL_H + +// Qt +#include +#include + +// Local +#include "document.h" +#include "imageutils/orientation.h" +namespace Gwenview { + + +class DocumentImpl : public QObject { +Q_OBJECT +public: + DocumentImpl(Document* document); + virtual ~DocumentImpl(); + /** + * This method is called by Document::switchToImpl after it has connect + * signals to the object + */ + virtual void init(); + + void switchToImpl(DocumentImpl*); + void setImage(QImage); + void setMimeType(const QString&); + void setImageFormat(const QCString&); + void setFileSize(int) const; + + /** + * Convenience method to emit rectUpdated with the whole image rect + */ + void emitImageRectUpdated(); + + virtual QString aperture() const; + virtual QString exposureTime() const; + virtual QString iso() const; + virtual QString focalLength() const; + + virtual QString comment() const; + virtual Document::CommentState commentState() const; + virtual void setComment(const QString&); + virtual int duration() const; + + virtual void transform(ImageUtils::Orientation); + virtual QString save(const KURL&, const QCString& format) const; + + virtual MimeTypeUtils::Kind urlKind() const=0; + + virtual bool canBeSaved() const=0; + + +signals: + void finished(bool success); + void sizeUpdated(); + void rectUpdated(const QRect&); + +protected: + Document* mDocument; +}; + +class DocumentEmptyImpl : public DocumentImpl { +public: + DocumentEmptyImpl(Document* document) + : DocumentImpl(document) { + setImage(QImage()); + setImageFormat(0); + setMimeType("application/x-zerosize"); + } + + MimeTypeUtils::Kind urlKind() const { + return MimeTypeUtils::KIND_UNKNOWN; + } + + bool canBeSaved() const { + return false; + } +}; + +} // namespace +#endif /* DOCUMENTIMPL_H */ + diff --git a/src/gvcore/documentjpegloadedimpl.cpp b/src/gvcore/documentjpegloadedimpl.cpp new file mode 100644 index 0000000..2f3250b --- /dev/null +++ b/src/gvcore/documentjpegloadedimpl.cpp @@ -0,0 +1,143 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Qt +#include +#include +#include +#include + +// KDE +#include +#include +#include + +// Local +#include "miscconfig.h" +#include "imageutils/jpegcontent.h" +#include "imageutils/imageutils.h" +#include "documentjpegloadedimpl.moc" +namespace Gwenview { + + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + + +class DocumentJPEGLoadedImplPrivate { +public: + ImageUtils::JPEGContent mJPEGContent; + +}; + + +DocumentJPEGLoadedImpl::DocumentJPEGLoadedImpl(Document* document, const QByteArray& rawData) +: DocumentLoadedImpl(document) { + LOG("" << mDocument->url().prettyURL() << ", data size: " << rawData.size() ); + d=new DocumentJPEGLoadedImplPrivate; + d->mJPEGContent.loadFromData(rawData); +} + + +void DocumentJPEGLoadedImpl::init() { + LOG(""); + ImageUtils::Orientation orientation=d->mJPEGContent.orientation(); + + if (MiscConfig::autoRotateImages() + && orientation!=ImageUtils::NOT_AVAILABLE + && orientation!=ImageUtils::NORMAL) + { + d->mJPEGContent.transform(orientation); + } + + DocumentLoadedImpl::init(); +} + + +DocumentJPEGLoadedImpl::~DocumentJPEGLoadedImpl() { + delete d; +} + + +void DocumentJPEGLoadedImpl::transform(ImageUtils::Orientation orientation) { + d->mJPEGContent.transform(orientation); + setImage(ImageUtils::transform(mDocument->image(), orientation)); + emitImageRectUpdated(); +} + + +QString DocumentJPEGLoadedImpl::localSave(QFile* file, const QCString& format) const { + if (qstrcmp(format, "JPEG")==0) { + LOG("JPEG Reset orientation"); + d->mJPEGContent.resetOrientation(); + if (!d->mJPEGContent.thumbnail().isNull()) { + d->mJPEGContent.setThumbnail( ImageUtils::scale( + mDocument->image(), 128, 128, ImageUtils::SMOOTH_FAST, QImage::ScaleMin)); + } + + LOG("JPEG Lossless save"); + if (!d->mJPEGContent.save(file)) { + return i18n("Could not save this JPEG file."); + } + } else { + QString msg=DocumentLoadedImpl::localSave(file, format); + if (!msg.isNull()) return msg; + } + + return QString::null; +} + + +QString DocumentJPEGLoadedImpl::comment() const { + return d->mJPEGContent.comment(); +} + +void DocumentJPEGLoadedImpl::setComment(const QString& comment) { + d->mJPEGContent.setComment(comment); +} + +QString DocumentJPEGLoadedImpl::aperture() const { + return d->mJPEGContent.aperture(); +} + +QString DocumentJPEGLoadedImpl::exposureTime() const { + return d->mJPEGContent.exposureTime(); +} + +QString DocumentJPEGLoadedImpl::iso() const { + return d->mJPEGContent.iso(); +} + +QString DocumentJPEGLoadedImpl::focalLength() const { + return d->mJPEGContent.focalLength(); +} + +Document::CommentState DocumentJPEGLoadedImpl::commentState() const { + return Document::WRITABLE; +} + + +} // namespace diff --git a/src/gvcore/documentjpegloadedimpl.h b/src/gvcore/documentjpegloadedimpl.h new file mode 100644 index 0000000..abb1e81 --- /dev/null +++ b/src/gvcore/documentjpegloadedimpl.h @@ -0,0 +1,62 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef DOCUMENTJPEGLOADEDIMPL_H +#define DOCUMENTJPEGLOADEDIMPL_H + +// Qt +#include + +// Local +#include "documentloadedimpl.h" +namespace Gwenview { + +class Document; + +class DocumentJPEGLoadedImplPrivate; + +class DocumentJPEGLoadedImpl : public DocumentLoadedImpl { +Q_OBJECT +public: + DocumentJPEGLoadedImpl(Document* document, const QByteArray& rawData); + ~DocumentJPEGLoadedImpl(); + void init(); + + QString comment() const; + void setComment(const QString&); + Document::CommentState commentState() const; + + QString aperture() const; + QString exposureTime() const; + QString iso() const; + QString focalLength() const; + + void transform(ImageUtils::Orientation); + +protected: + QString localSave(QFile*, const QCString& format) const; + +private: + DocumentJPEGLoadedImplPrivate* d; +}; + +} // namespace +#endif /* DOCUMENTJPEGLOADEDIMPL_H */ + diff --git a/src/gvcore/documentloadedimpl.cpp b/src/gvcore/documentloadedimpl.cpp new file mode 100644 index 0000000..1d9456a --- /dev/null +++ b/src/gvcore/documentloadedimpl.cpp @@ -0,0 +1,198 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "documentloadedimpl.moc" + +#include +#include +#include +#include + +// Qt +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include + +// Local +#include "imageutils/imageutils.h" +namespace Gwenview { + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + + +class DocumentLoadedImplPrivate { + int mSize; + QDateTime mModified; +}; + +DocumentLoadedImpl::DocumentLoadedImpl(Document* document) +: DocumentImpl(document) { + LOG(""); +} + + +void DocumentLoadedImpl::init() { + emit finished(true); +} + + +DocumentLoadedImpl::~DocumentLoadedImpl() { +} + + +void DocumentLoadedImpl::transform(ImageUtils::Orientation orientation) { + setImage(ImageUtils::transform(mDocument->image(), orientation)); + emitImageRectUpdated(); +} + + +QString DocumentLoadedImpl::save(const KURL& _url, const QCString& format) const { + if (!QImageIO::outputFormats().contains(format)) { + return i18n("Gwenview cannot write files in this format."); + } + + QString msg; + KURL url(_url); + + // Use the umask to determine default mode (will be used if the dest file + // does not exist) + int _umask=umask(0); + umask(_umask); + mode_t mode=0666 & ~_umask; + + if (url.isLocalFile()) { + // If the file is a link, dereference it but take care of circular + // links + QFileInfo info(url.path()); + if (info.isSymLink()) { + QStringList links; + while (info.isSymLink()) { + links.append(info.filePath()); + QString path=info.readLink(); + if (path[0]!='/') { + path=info.dirPath(true) + '/' + path; + } + path=QDir::cleanDirPath(path); + if (links.contains(path)) { + return i18n("This is a circular link."); + } + info.setFile(path); + } + url.setPath(info.filePath()); + } + + + // Make some quick tests on the file if it is local + if (info.exists() && ! info.isWritable()) { + return i18n("This file is read-only."); + } + + if (info.exists()) { + // Get current file mode + KDE_struct_stat st; + if (KDE_stat(QFile::encodeName(info.filePath()), &st)==0) { + mode=st.st_mode & 07777; + } else { + // This should not happen + kdWarning() << "Could not stat " << info.filePath() << endl; + } + + } else { + QFileInfo parent=QFileInfo(info.dirPath()); + if (!parent.isWritable()) { + return + i18n("The %1 folder is read-only.") + .arg(parent.filePath()); + } + } + } + + // Save the file to a tmp file + QString prefix; + if (url.isLocalFile()) { + // We set the prefix to url.path() so that the temp file is on the + // same partition as the destination file. If we don't do this, rename + // will fail + prefix=url.path(); + } + KTempFile tmp(prefix, "gwenview", mode); + tmp.setAutoDelete(true); + if (tmp.status()!=0) { + QString reason( strerror(tmp.status()) ); + return i18n("Could not create a temporary file.\nReason: %1.") + .arg(reason); + } + QFile* file=tmp.file(); + msg=localSave(file, format); + if (!msg.isNull()) return msg; + file->close(); + + if (tmp.status()!=0) { + QString reason( strerror(tmp.status()) ); + return i18n("Saving image to a temporary file failed.\nReason: %1.") + .arg(reason); + } + + QString tmpName=tmp.name(); + int tmpSize=QFileInfo(tmpName).size(); + setFileSize(tmpSize); + + // Move the tmp file to the final dest + if (url.isLocalFile()) { + if( ::rename( QFile::encodeName(tmpName), QFile::encodeName( url.path())) < 0 ) { + return i18n("Could not write to %1.").arg(url.path()); + } + } else { + if (!KIO::NetAccess::upload(tmp.name(), url, KApplication::kApplication()->mainWidget() )) { + return i18n("Could not upload the file to %1.").arg(url.prettyURL()); + } + } + + return QString::null; +} + + +QString DocumentLoadedImpl::localSave(QFile* file, const QCString& format) const { + QImageIO iio(file, format); + iio.setImage(mDocument->image()); + if (!iio.write()) { + return + i18n("An error happened while saving."); + } + return QString::null; +} + + +} // namespace diff --git a/src/gvcore/documentloadedimpl.h b/src/gvcore/documentloadedimpl.h new file mode 100644 index 0000000..27a8ea7 --- /dev/null +++ b/src/gvcore/documentloadedimpl.h @@ -0,0 +1,54 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef DOCUMENTLOADEDIMPL_H +#define DOCUMENTLOADEDIMPL_H + +// Qt +#include + +// Local +#include "documentimpl.h" + +class QFile; + +namespace Gwenview { +class Document; + +class DocumentLoadedImpl : public DocumentImpl { +Q_OBJECT +public: + DocumentLoadedImpl(Document* document); + void init(); + ~DocumentLoadedImpl(); + + void transform(ImageUtils::Orientation); + QString save(const KURL&, const QCString& format) const; + + virtual MimeTypeUtils::Kind urlKind() const { return MimeTypeUtils::KIND_RASTER_IMAGE; } + virtual bool canBeSaved() const { return true; } + +protected: + virtual QString localSave(QFile* file, const QCString& format) const; +}; + +} // namespace +#endif /* DOCUMENTLOADEDIMPL_H */ + diff --git a/src/gvcore/documentloadingimpl.cpp b/src/gvcore/documentloadingimpl.cpp new file mode 100644 index 0000000..e148543 --- /dev/null +++ b/src/gvcore/documentloadingimpl.cpp @@ -0,0 +1,165 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "documentloadingimpl.moc" + +// Qt + +// KDE +#include + +// Local +#include "imageloader.h" +#include "documentotherloadedimpl.h" +#include "documentanimatedloadedimpl.h" +#include "documentloadedimpl.h" +#include "documentjpegloadedimpl.h" +#include "mimetypeutils.h" + +namespace Gwenview { + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +//--------------------------------------------------------------------- +// +// DocumentLoadingImplPrivate +// +//--------------------------------------------------------------------- + +class DocumentLoadingImplPrivate { +public: + DocumentLoadingImplPrivate() + : mLoader( NULL ) + {} + + ImageLoader* mLoader; +}; + +//--------------------------------------------------------------------- +// +// DocumentLoadingImpl +// +//--------------------------------------------------------------------- +DocumentLoadingImpl::DocumentLoadingImpl(Document* document) +: DocumentImpl(document) { + LOG(""); + d=new DocumentLoadingImplPrivate; +} + + +DocumentLoadingImpl::~DocumentLoadingImpl() { + LOG(""); + delete d; +} + + +void DocumentLoadingImpl::init() { + LOG(""); + d->mLoader = ImageLoader::loader( mDocument->url(), this, BUSY_LOADING ); + if (d->mLoader->urlKind()==MimeTypeUtils::KIND_FILE) { + LOG("urlKind already determined"); + switchToImpl(new DocumentOtherLoadedImpl(mDocument)); + return; + } + connect( d->mLoader, SIGNAL( urlKindDetermined()), SLOT( slotURLKindDetermined() )); + connect( d->mLoader, SIGNAL( sizeLoaded( int, int )), SLOT( sizeLoaded( int, int ))); + connect( d->mLoader, SIGNAL( imageChanged( const QRect& )), SLOT( imageChanged( const QRect& ))); + connect( d->mLoader, SIGNAL( imageLoaded( bool )), SLOT( imageLoaded( bool ))); + + // it's possible the loader already has the whole or at least part of the image loaded + QImage image = d->mLoader->processedImage(); + if (!image.isNull()) { + if( d->mLoader->frames().count() > 0 ) { + setImage( d->mLoader->frames().first().image); + emitImageRectUpdated(); + } else { + setImage(image); + QMemArray< QRect > rects = d->mLoader->loadedRegion().rects(); + for( unsigned int i = 0; i < rects.count(); ++i ) { + emit rectUpdated(rects[i]); + } + } + } + if( d->mLoader->completed()) imageLoaded( d->mLoader->frames().count() != 0 ); + // 'this' may be deleted here +} + + +void DocumentLoadingImpl::slotURLKindDetermined() { + LOG(""); + if (d->mLoader->urlKind()==MimeTypeUtils::KIND_FILE) { + switchToImpl(new DocumentOtherLoadedImpl(mDocument)); + } +} + + +void DocumentLoadingImpl::imageLoaded( bool ok ) { + LOG(""); + + QCString format = d->mLoader->imageFormat(); + if ( !ok || format.isEmpty()) { + // Unknown format, no need to go further + emit finished(false); + switchToImpl(new DocumentEmptyImpl(mDocument)); + return; + } + setImageFormat( format ); + setMimeType(d->mLoader->mimeType()); + + // Update file info + setFileSize(d->mLoader->rawData().size()); + + // Now we switch to a loaded implementation + if ( d->mLoader->frames().count() > 1 ) { + switchToImpl( new DocumentAnimatedLoadedImpl(mDocument, d->mLoader->frames())); + } else if ( format == "JPEG" ) { + switchToImpl( new DocumentJPEGLoadedImpl(mDocument, d->mLoader->rawData()) ); + } else { + switchToImpl(new DocumentLoadedImpl(mDocument)); + } +} + + +void DocumentLoadingImpl::imageChanged(const QRect& rect) { + LOG(rect); + setImage(d->mLoader->processedImage()); + emit rectUpdated(rect); +} + + +void DocumentLoadingImpl::sizeLoaded(int width, int height) { + LOG(width << "x" << height); + // Silence compiler + width=width; + height=height; + + setImage(d->mLoader->processedImage()); + emit sizeUpdated(); +} + +} // namespace diff --git a/src/gvcore/documentloadingimpl.h b/src/gvcore/documentloadingimpl.h new file mode 100644 index 0000000..a17b25d --- /dev/null +++ b/src/gvcore/documentloadingimpl.h @@ -0,0 +1,55 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef DOCUMENTLOADINGIMPL_H +#define DOCUMENTLOADINGIMPL_H + +// Local +#include "documentimpl.h" +#include "mimetypeutils.h" + +namespace Gwenview { + +class Document; + +class DocumentLoadingImplPrivate; + +class DocumentLoadingImpl : public DocumentImpl { +Q_OBJECT +public: + DocumentLoadingImpl(Document* document); + ~DocumentLoadingImpl(); + virtual void init(); + virtual MimeTypeUtils::Kind urlKind() const { return MimeTypeUtils::KIND_RASTER_IMAGE; } + virtual bool canBeSaved() const { return false; } + +private: + DocumentLoadingImplPrivate* d; + +private slots: + void slotURLKindDetermined(); + void sizeLoaded(int, int); + void imageChanged(const QRect&); + void imageLoaded( bool ok ); +}; + +} // namespace +#endif /* DOCUMENTLOADINGIMPL_H */ + diff --git a/src/gvcore/documentotherloadedimpl.cpp b/src/gvcore/documentotherloadedimpl.cpp new file mode 100644 index 0000000..1e3674b --- /dev/null +++ b/src/gvcore/documentotherloadedimpl.cpp @@ -0,0 +1,58 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2006 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Self +#include "documentotherloadedimpl.h" + +// KDE +#include +#include + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +namespace Gwenview { + +int DocumentOtherLoadedImpl::duration() const { + KFileMetaInfo fmi(mDocument->url()); + if (!fmi.isValid()) { + LOG("No meta info available for " << mDocument->url()); + return 0; + } + + KFileMetaInfoItem item=fmi.item("Length"); + if (!item.isValid()) { + kdWarning() << "Can't adjust slideshow time: meta info for " << mDocument->url() << " does not contain 'Length' information."; + return 0; + } + + int length = item.value().toInt(); + LOG("Length for " << mDocument->url() << " is " << length); + + return length; +} + +} // namespace diff --git a/src/gvcore/documentotherloadedimpl.h b/src/gvcore/documentotherloadedimpl.h new file mode 100644 index 0000000..d9ffbdb --- /dev/null +++ b/src/gvcore/documentotherloadedimpl.h @@ -0,0 +1,52 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2006 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef DOCUMENTOTHERLOADEDIMPL_H +#define DOCUMENTOTHERLOADEDIMPL_H + +// Local +#include "document.h" +#include "documentimpl.h" + +namespace Gwenview { +class Document; + +class DocumentOtherLoadedImpl : public DocumentImpl { +public: + DocumentOtherLoadedImpl(Document* document) + : DocumentImpl(document) { + setImage(QImage()); + setImageFormat(0); + } + + void init() { + emit finished(true); + } + + virtual MimeTypeUtils::Kind urlKind() const { return MimeTypeUtils::KIND_FILE; } + + virtual bool canBeSaved() const { return false; } + + virtual int duration() const; +}; + +} // namespace +#endif /* DOCUMENTOTHERLOADEDIMPL_H */ + diff --git a/src/gvcore/dragpixmapgenerator.h b/src/gvcore/dragpixmapgenerator.h new file mode 100644 index 0000000..7699eed --- /dev/null +++ b/src/gvcore/dragpixmapgenerator.h @@ -0,0 +1,179 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurélien Gâteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef DRAGPIXMAPGENERATOR_H +#define DRAGPIXMAPGENERATOR_H + +// Qt +#include +#include +#include +#include +#include + +// KDE +#include + +namespace Gwenview { + + +template +class DragPixmapGenerator; + + +template +class DragPixmapItemDrawer { +public: + DragPixmapItemDrawer() + : mGenerator(0) {} + virtual ~DragPixmapItemDrawer() {} + virtual void setGenerator(DragPixmapGenerator* generator) { + mGenerator = generator; + } + virtual QSize itemSize(T)=0; + virtual void drawItem(QPainter*, int left, int top, T)=0; + virtual int spacing() const { + return 0; + } + +protected: + DragPixmapGenerator* mGenerator; +}; + + +QPixmap dragPixmapGeneratorHelper(QValueVector pixmapVector); + + +template +class DragPixmapGenerator { +public: + /** Offset between cursor and dragged images */ + static const uint DRAG_OFFSET=16; + + + /** Maximum width of an item painted by DragPixmapItemDrawer */ + static const int ITEM_MAX_WIDTH=128; + + static const int MAX_HEIGHT=200; + + static const int DRAG_MARGIN=4; + + + DragPixmapGenerator() + : mPixmapWidth(0) {} + + + void addItem(const T& item) { + mItemList << item; + } + + + int maxWidth() const { + return ITEM_MAX_WIDTH; + } + + + /** + * Returns the width of the generated pixmap, not including the margin. + * To be used by DragPixmapItemDrawer::drawItem. Should not be used + * anywhere else since this value is initialized in generate(). + */ + int pixmapWidth() const { + return mPixmapWidth; + } + + void setItemDrawer(DragPixmapItemDrawer* drawer) { + mItemDrawer = drawer; + drawer->setGenerator(this); + } + + QPixmap generate() { + int width = 0, height = 0; + int dragCount = 0; + int spacing = mItemDrawer->spacing(); + bool listCropped; + QString bottomText; + QFontMetrics fm = QApplication::fontMetrics(); + + // Compute pixmap size and update dragCount + QValueListIterator it = mItemList.begin(); + QValueListIterator end = mItemList.end(); + height = -spacing; + for (; it!= end && height < MAX_HEIGHT; ++dragCount, ++it) { + QSize itemSize = mItemDrawer->itemSize(*it); + Q_ASSERT(itemSize.width() <= ITEM_MAX_WIDTH); + + width = QMAX(width, itemSize.width()); + height += itemSize.height() + spacing; + } + + listCropped = it != end; + if (listCropped) { + // If list has been cropped, leave space for item count text + height += fm.height(); + bottomText = i18n("%1 items").arg(mItemList.count()); + width = QMAX(width, fm.width("... " + bottomText)); + } + + mPixmapWidth = width; + + // Init pixmap + QPixmap pixmap(width + 2*DRAG_MARGIN, height + 2*DRAG_MARGIN); + QColorGroup cg = QToolTip::palette().active(); + + pixmap.fill(cg.base()); + QPainter painter(&pixmap); + + // Draw border + painter.setPen(cg.dark()); + painter.drawRect(pixmap.rect()); + + // Draw items + it = mItemList.begin(); + height = DRAG_MARGIN; + for (int pos=0; pos < dragCount; ++pos, ++it) { + mItemDrawer->drawItem(&painter, DRAG_MARGIN, height, *it); + height += mItemDrawer->itemSize(*it).height() + spacing; + } + + // Draw text if necessary + if (listCropped) { + int posY= height + fm.ascent(); + painter.drawText(DRAG_MARGIN, posY, "..."); + int offset = width - fm.width(bottomText); + painter.drawText(DRAG_MARGIN + offset, posY, bottomText); + } + painter.end(); + + return pixmap; + } + + +private: + QValueList mItemList; + DragPixmapItemDrawer* mItemDrawer; + int mPixmapWidth; +}; + + +} // namespace + + +#endif /* DRAGPIXMAPGENERATOR_H */ diff --git a/src/gvcore/externaltoolaction.cpp b/src/gvcore/externaltoolaction.cpp new file mode 100644 index 0000000..db47ff8 --- /dev/null +++ b/src/gvcore/externaltoolaction.cpp @@ -0,0 +1,56 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Qt +#include + +// KDE +#include +#include +#include + +// Local +#include "externaltoolaction.moc" +namespace Gwenview { + +ExternalToolAction::ExternalToolAction( + QObject* parent, const KService* service, + const KURL::List& urls) +: KAction(parent) +, mService(service) +, mURLs(urls) +{ + setText(service->name()); + setIcon(service->icon()); + connect(this, SIGNAL(activated()), + this, SLOT(openExternalTool()) ); + +} + + +void ExternalToolAction::openExternalTool() { + QString dir=mURLs.first().directory(); + QDir::setCurrent(dir); + + QStringList args=KRun::processDesktopExec(*mService, mURLs, true); + KRun::runCommand(args.join(" "), mService->name(), mService->icon()); +} + +} // namespace diff --git a/src/gvcore/externaltoolaction.h b/src/gvcore/externaltoolaction.h new file mode 100644 index 0000000..7f62160 --- /dev/null +++ b/src/gvcore/externaltoolaction.h @@ -0,0 +1,50 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef EXTERNALTOOLACTION_H +#define EXTERNALTOOLACTION_H + +// KDE +#include +#include + +class KService; + +namespace Gwenview { +/** + * A specialized version of KAction, which is aware of the tool to run as well + * as the urls to call it with. + */ +class ExternalToolAction : public KAction { +Q_OBJECT +public: + ExternalToolAction(QObject* parent, const KService*, const KURL::List&); + +private slots: + void openExternalTool(); + +private: + const KService* mService; + const KURL::List& mURLs; +}; + +} // namespace +#endif + diff --git a/src/gvcore/externaltoolcontext.cpp b/src/gvcore/externaltoolcontext.cpp new file mode 100644 index 0000000..fef6ac0 --- /dev/null +++ b/src/gvcore/externaltoolcontext.cpp @@ -0,0 +1,80 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "externaltoolcontext.moc" + +// KDE +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "externaltoolaction.h" +#include "externaltooldialog.h" + +namespace Gwenview { + +ExternalToolContext::ExternalToolContext( + QObject* parent, + std::list services, + KURL::List urls) +: QObject(parent) +, mServices(services) +, mURLs(urls) +{} + + +void ExternalToolContext::showExternalToolDialog() { + ExternalToolDialog* dialog=new ExternalToolDialog(kapp->mainWidget()); + dialog->show(); +} + + +void ExternalToolContext::showOpenWithDialog() { + KRun::displayOpenWithDialog(mURLs, false /*tempFiles*/); +} + + +QPopupMenu* ExternalToolContext::popupMenu() { + QPopupMenu* menu=new QPopupMenu(); + std::list::const_iterator it=mServices.begin(); + std::list::const_iterator itEnd=mServices.end(); + for (;it!=itEnd; ++it) { + ExternalToolAction* action= + new ExternalToolAction(this, *it, mURLs); + action->plug(menu); + } + + menu->insertSeparator(); + menu->insertItem(i18n("Other..."), + this, SLOT(showOpenWithDialog()) ); + menu->insertItem( + SmallIcon("configure"), + i18n("Configure External Tools..."), + this, SLOT(showExternalToolDialog()) ); + + return menu; +} + +} // namespace diff --git a/src/gvcore/externaltoolcontext.h b/src/gvcore/externaltoolcontext.h new file mode 100644 index 0000000..a253ede --- /dev/null +++ b/src/gvcore/externaltoolcontext.h @@ -0,0 +1,59 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef EXTERNALTOOLCONTEXT_H +#define EXTERNALTOOLCONTEXT_H + +// STL +#include + +// Qt +#include + +// KDE +#include + +// Local +#include "libgwenview_export.h" + +class QPopupMenu; +class KService; + +namespace Gwenview { +class LIBGWENVIEW_EXPORT ExternalToolContext : public QObject { +Q_OBJECT +public: + ExternalToolContext(QObject* parent, + std::list services, + KURL::List urls); + QPopupMenu* popupMenu(); + +private slots: + void showExternalToolDialog(); + void showOpenWithDialog(); + +private: + std::list mServices; + KURL::List mURLs; +}; + +} // namespace +#endif + diff --git a/src/gvcore/externaltooldialog.cpp b/src/gvcore/externaltooldialog.cpp new file mode 100644 index 0000000..89ffb79 --- /dev/null +++ b/src/gvcore/externaltooldialog.cpp @@ -0,0 +1,355 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Qt +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "archive.h" +#include "mimetypeutils.h" +#include "externaltoolmanager.h" +#include "externaltooldialogbase.h" +#include "externaltooldialog.moc" +namespace Gwenview { + + +enum { ID_ALL_IMAGES=0, ID_ALL_FILES, ID_CUSTOM }; + + +class ToolListViewItem : public KListViewItem { +public: + ToolListViewItem(KListView* parent, const QString& label) + : KListViewItem(parent, label), mDesktopFile(0L) {} + + void setDesktopFile(KDesktopFile* df) { + mDesktopFile=df; + } + + KDesktopFile* desktopFile() const { + return mDesktopFile; + } + +private: + KDesktopFile* mDesktopFile; +}; + + +struct ExternalToolDialogPrivate { + ExternalToolDialogBase* mContent; + QPtrList mDeletedTools; + ToolListViewItem* mSelectedItem; + + + ExternalToolDialogPrivate() + : mSelectedItem(0L) {} + + void fillMimeTypeListView() { + QStringList mimeTypes=MimeTypeUtils::rasterImageMimeTypes(); + mimeTypes.append("inode/directory"); + mimeTypes+=Archive::mimeTypes(); + + QStringList::const_iterator it=mimeTypes.begin(); + for(; it!=mimeTypes.end(); ++it) { + (void)new QCheckListItem(mContent->mMimeTypeListView, *it, QCheckListItem::CheckBox); + } + } + + + void fillToolListView() { + QDict desktopFiles=ExternalToolManager::instance()->desktopFiles(); + + QDictIterator it(desktopFiles); + for (; it.current(); ++it) { + ToolListViewItem* item=new ToolListViewItem(mContent->mToolListView, it.current()->readName()); + item->setPixmap(0, SmallIcon(it.current()->readIcon()) ); + item->setDesktopFile(it.current()); + } + mContent->mToolListView->setSortColumn(0); + mContent->mToolListView->sort(); + } + + + void writeServiceTypes(KDesktopFile* desktopFile) { + QButton* button=mContent->mFileAssociationGroup->selected(); + if (!button) { + desktopFile->writeEntry("ServiceTypes", "*"); + return; + } + + int id=mContent->mFileAssociationGroup->id(button); + if (id==ID_ALL_IMAGES) { + desktopFile->writeEntry("ServiceTypes", "image/*"); + return; + } + if (id==ID_ALL_FILES) { + desktopFile->writeEntry("ServiceTypes", "*"); + return; + } + + QStringList mimeTypes; + QListViewItem* item=mContent->mMimeTypeListView->firstChild(); + for (; item; item=item->nextSibling()) { + if (static_cast(item)->isOn()) { + mimeTypes.append(item->text(0)); + } + } + desktopFile->writeEntry("ServiceTypes", mimeTypes); + } + + + bool saveChanges() { + if (!mSelectedItem) return true; + + // Check name + QString name=mContent->mName->text().stripWhiteSpace(); + if (name.isEmpty()) { + KMessageBox::sorry(mContent, i18n("The tool name cannot be empty")); + return false; + } + + QListViewItem* item=mContent->mToolListView->firstChild(); + for (; item; item=item->nextSibling()) { + if (item==mSelectedItem) continue; + if (name==item->text(0)) { + KMessageBox::sorry(mContent, i18n("There is already a tool named \"%1\"").arg(name)); + return false; + } + } + + // Save data + KDesktopFile* desktopFile=mSelectedItem->desktopFile(); + if (desktopFile) { + if (desktopFile->isReadOnly()) { + desktopFile=ExternalToolManager::instance()->editSystemDesktopFile(desktopFile); + mSelectedItem->setDesktopFile(desktopFile); + } + } else { + desktopFile=ExternalToolManager::instance()->createUserDesktopFile(name); + mSelectedItem->setDesktopFile(desktopFile); + } + desktopFile->writeEntry("Name", name); + desktopFile->writeEntry("Icon", mContent->mIconButton->icon()); + desktopFile->writeEntry("Exec", mContent->mCommand->url()); + writeServiceTypes(desktopFile); + + mSelectedItem->setPixmap(0, SmallIcon(mContent->mIconButton->icon()) ); + mSelectedItem->setText(0, name); + + return true; + } + + + void updateFileAssociationGroup(const QStringList& serviceTypes) { + QListViewItem* item=mContent->mMimeTypeListView->firstChild(); + for (; item; item=item->nextSibling()) { + static_cast(item)->setOn(false); + } + + if (serviceTypes.size()==0) { + mContent->mFileAssociationGroup->setButton(ID_ALL_FILES); + return; + } + if (serviceTypes.size()==1) { + QString serviceType=serviceTypes[0]; + if (serviceType=="image/*") { + mContent->mFileAssociationGroup->setButton(ID_ALL_IMAGES); + return; + } + if (serviceType=="*") { + mContent->mFileAssociationGroup->setButton(ID_ALL_FILES); + return; + } + } + + mContent->mFileAssociationGroup->setButton(ID_CUSTOM); + QStringList::ConstIterator it=serviceTypes.begin(); + for (;it!=serviceTypes.end(); ++it) { + QListViewItem* item= + mContent->mMimeTypeListView->findItem(*it, 0, Qt::ExactMatch); + if (item) static_cast(item)->setOn(true); + } + } + + + void updateDetails() { + mContent->mDetails->setEnabled(mSelectedItem!=0); + + if (mSelectedItem) { + KDesktopFile* desktopFile=mSelectedItem->desktopFile(); + if (desktopFile) { + mContent->mName->setText(desktopFile->readName()); + mContent->mCommand->setURL(desktopFile->readEntry("Exec")); + mContent->mIconButton->setIcon(desktopFile->readIcon()); + QStringList serviceTypes=desktopFile->readListEntry("ServiceTypes"); + updateFileAssociationGroup(serviceTypes); + return; + } + } + + mContent->mName->setText(QString::null); + mContent->mCommand->setURL(QString::null); + mContent->mIconButton->setIcon(QString::null); + mContent->mFileAssociationGroup->setButton(ID_ALL_IMAGES); + } + + bool apply() { + if (!saveChanges()) return false; + QPtrListIterator it(mDeletedTools); + for(; it.current(); ++it) { + ExternalToolManager::instance()->hideDesktopFile(it.current()); + } + ExternalToolManager::instance()->updateServices(); + return true; + } +}; + + +/** + * This event filter object is here to prevent the user from selecting a + * different tool in the tool list view if the current tool could not be saved. + */ +class ToolListViewFilterObject : public QObject { + ExternalToolDialogPrivate* d; +public: + ToolListViewFilterObject(QObject* parent, ExternalToolDialogPrivate* _d) + : QObject(parent), d(_d) {} + + bool eventFilter(QObject*, QEvent* event) { + if (event->type()!=QEvent::MouseButtonPress) return false; + return !d->saveChanges(); + } +}; + + +ExternalToolDialog::ExternalToolDialog(QWidget* parent) +: KDialogBase( + parent,0, false, QString::null, KDialogBase::Ok|KDialogBase::Apply|KDialogBase::Cancel, + KDialogBase::Ok, true) +{ + setWFlags(getWFlags() | Qt::WDestructiveClose); + d=new ExternalToolDialogPrivate; + + d->mContent=new ExternalToolDialogBase(this); + setMainWidget(d->mContent); + setCaption(d->mContent->caption()); + + d->mContent->mToolListView->header()->hide(); + d->mContent->mMimeTypeListView->header()->hide(); + + d->fillMimeTypeListView(); + d->fillToolListView(); + d->mContent->mToolListView->viewport()->installEventFilter( + new ToolListViewFilterObject(this, d)); + + connect( d->mContent->mToolListView, SIGNAL(selectionChanged(QListViewItem*)), + this, SLOT(slotSelectionChanged(QListViewItem*)) ); + connect( d->mContent->mAddButton, SIGNAL(clicked()), + this, SLOT(addTool()) ); + connect( d->mContent->mDeleteButton, SIGNAL(clicked()), + this, SLOT(deleteTool()) ); + connect( d->mContent->mHelp, SIGNAL(leftClickedURL()), + this, SLOT(showCommandHelp()) ); + connect( d->mContent->mMoreTools, SIGNAL(leftClickedURL(const QString&)), + this, SLOT(openURL(const QString&)) ); + + KListView* view=d->mContent->mToolListView; + if (view->firstChild()) { + view->setSelected(view->firstChild(), true); + } + d->updateDetails(); +} + + +ExternalToolDialog::~ExternalToolDialog() { + delete d; +} + + +void ExternalToolDialog::slotOk() { + if (!d->apply()) return; + accept(); +} + + +void ExternalToolDialog::slotApply() { + d->apply(); +} + + +void ExternalToolDialog::slotCancel() { + KDialogBase::slotCancel(); +} + + +void ExternalToolDialog::slotSelectionChanged(QListViewItem* item) { + d->mSelectedItem=static_cast(item); + d->updateDetails(); +} + + +void ExternalToolDialog::addTool() { + KListView* view=d->mContent->mToolListView; + QString name=i18n(""); + ToolListViewItem* item=new ToolListViewItem(view, name); + view->setSelected(item, true); +} + + +void ExternalToolDialog::deleteTool() { + KListView* view=d->mContent->mToolListView; + ToolListViewItem* item=static_cast(view->selectedItem()); + if (!item) return; + + KDesktopFile* desktopFile=item->desktopFile(); + delete item; + d->mDeletedTools.append(desktopFile); + d->mSelectedItem=0L; + d->updateDetails(); +} + + +void ExternalToolDialog::showCommandHelp() { + KURLRequester* lbl=d->mContent->mCommand; + QWhatsThis::display(QWhatsThis::textFor(lbl), + lbl->mapToGlobal( lbl->rect().bottomRight() ) ); +} + + +void ExternalToolDialog::openURL(const QString& url) { + new KRun(KURL(url)); +} + +} // namespace diff --git a/src/gvcore/externaltooldialog.h b/src/gvcore/externaltooldialog.h new file mode 100644 index 0000000..306cb59 --- /dev/null +++ b/src/gvcore/externaltooldialog.h @@ -0,0 +1,59 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef EXTERNALTOOLDIALOG_H +#define EXTERNALTOOLDIALOG_H + +// KDE +#include + +// Our includes +#include "libgwenview_export.h" + +namespace Gwenview { + + +class ExternalToolDialogPrivate; +class LIBGWENVIEW_EXPORT ExternalToolDialog : public KDialogBase { +Q_OBJECT +public: + ExternalToolDialog(QWidget* parent); + ~ExternalToolDialog(); + +protected slots: + void slotOk(); + void slotApply(); + void slotCancel(); + +private slots: + void slotSelectionChanged(QListViewItem*); + void addTool(); + void deleteTool(); + void showCommandHelp(); + void openURL(const QString& url); + +private: + ExternalToolDialogPrivate* d; +}; + + +} // namespace +#endif + diff --git a/src/gvcore/externaltooldialogbase.ui b/src/gvcore/externaltooldialogbase.ui new file mode 100644 index 0000000..7b17ed4 --- /dev/null +++ b/src/gvcore/externaltooldialogbase.ui @@ -0,0 +1,373 @@ + +ExternalToolDialogBase + + + ExternalToolDialogBase + + + + 0 + 0 + 723 + 361 + + + + + 5 + 5 + 0 + 0 + + + + + 720 + 0 + + + + Configure External Tools + + + + unnamed + + + 0 + + + 6 + + + + spacer3_2 + + + Horizontal + + + Expanding + + + + 487 + 16 + + + + + + mDeleteButton + + + &Delete + + + + + mAddButton + + + &Add + + + + + + Name + + + false + + + true + + + + mToolListView + + + + 5 + 7 + 0 + 0 + + + + true + + + + + mMoreTools + + + Get more tools + + + http://gwenview.sourceforge.net/tools + + + true + + + + + mDetails + + + NoFrame + + + Raised + + + + unnamed + + + 0 + + + + textLabel1_2 + + + + 5 + 0 + 0 + 0 + + + + + 1 + + + + File Associations + + + + + layout3 + + + + unnamed + + + + mIconButton + + + + 1 + 1 + 0 + 0 + + + + + + + + + textLabel1 + + + Name: + + + + + mHelp + + + Help + + + + + + + + textLabel2 + + + Command: + + + + + mName + + + + + mCommand + + + + 7 + 5 + 0 + 0 + + + + <qt> +You can use keywords in the Command field: +<ul> +<li><tt>%u</tt>: Current URL.</li> +<li><tt>%U</tt>: Current URLs. Use this if the tool can handle multiple files.</li> +<li><tt>%f</tt>: Current file. Use this if the tool can't handle URLs.</li> +<li><tt>%F</tt>: Same as %f, but for multiple files.</li> +</ul> +</qt> + + + + + + + mFileAssociationGroup + + + + 5 + 7 + 0 + 1 + + + + NoFrame + + + + + + + unnamed + + + 0 + + + 6 + + + + radioButton1 + + + All images + + + true + + + 0 + + + + + radioButton2 + + + All files + + + 1 + + + + + radioButton3 + + + Custom: + + + + + spacer3 + + + Vertical + + + Expanding + + + + 21 + 140 + + + + + + + Mime Type + + + false + + + true + + + + mMimeTypeListView + + + false + + + true + + + + + + + + + + + + + radioButton3 + toggled(bool) + mMimeTypeListView + setEnabled(bool) + + + + mToolListView + mAddButton + mDeleteButton + mName + mCommand + radioButton1 + mMimeTypeListView + + + + klistview.h + kurllabel.h + kicondialog.h + kurllabel.h + klineedit.h + kurlrequester.h + klineedit.h + kpushbutton.h + klistview.h + + diff --git a/src/gvcore/externaltoolmanager.cpp b/src/gvcore/externaltoolmanager.cpp new file mode 100644 index 0000000..1df124f --- /dev/null +++ b/src/gvcore/externaltoolmanager.cpp @@ -0,0 +1,294 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// STL +#include + +// Qt +#include + +// KDE +#include +#include +#include +#include +#include +#include + +// Local +#include "externaltoolcontext.h" +#include "externaltoolmanager.h" +namespace Gwenview { + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +// Helper functions for createContextInternal +inline bool mimeTypeMatches(const QString& candidate, const QString& reference) { + if (reference=="*") return true; + + if (reference.right(1)=="*") { + return candidate.startsWith(reference.left(reference.length()-1)); + } else { + return candidate==reference; + } +} + +inline bool isSubSetOf(const QStringList& subSet, const QStringList& set) { + // Simple implementation, might need some optimization + QStringList::ConstIterator itSubSet=subSet.begin(); + QStringList::ConstIterator itSetBegin=set.begin(); + QStringList::ConstIterator itSetEnd=set.end(); + + for (; itSubSet!=subSet.end(); ++itSubSet) { + bool matchFound=false; + QStringList::ConstIterator itSet=itSetBegin; + for (; itSet!=itSetEnd; ++itSet) { + if (mimeTypeMatches(*itSubSet, *itSet)) { + matchFound=true; + break; + } + } + if (!matchFound) { + return false; + } + } + return true; +} + + +struct ExternalToolManagerPrivate { + QDict mDesktopFiles; + QPtrList mServices; + QString mUserToolDir; + + /** + * Helper function for createContextInternal + */ + static bool compareKServicePtrByName(const KService* s1, const KService* s2) { + Q_ASSERT(s1); + Q_ASSERT(s2); + return s1->name() < s2->name(); + } + + ExternalToolContext* createContextInternal( + QObject* parent, const KURL::List& urls, const QStringList& mimeTypes) + { + bool onlyOneURL=urls.size()==1; + + // Only add to selectionServices the services which can handle all the + // different mime types present in the selection + // + // We use std::list instead of QValueList because it's not possible to + // pass a sort functor to qHeapSort + std::list selectionServices; + QPtrListIterator it(mServices); + for (; it.current(); ++it) { + KService* service=it.current(); + if (!onlyOneURL && !service->allowMultipleFiles()) { + continue; + } + + QStringList serviceTypes=service->serviceTypes(); + if (isSubSetOf(mimeTypes, serviceTypes)) { + selectionServices.push_back(service); + } + } + selectionServices.sort(compareKServicePtrByName); + + return new ExternalToolContext(parent, selectionServices, urls); + } + +}; + + +// Helper function for ctor +void loadDesktopFiles(QDict& dict, const QString& dirString) { + QDir dir(dirString); + QStringList list=dir.entryList("*.desktop"); + QStringList::ConstIterator it=list.begin(); + for (; it!=list.end(); ++it) { + KDesktopFile* df=new KDesktopFile( dir.filePath(*it) ); + dict.insert(*it, df); + } +} + +inline QString addSlash(const QString& _str) { + QString str(_str); + if (str.right(1)!="/") str.append('/'); + return str; +} + +ExternalToolManager::ExternalToolManager() { + d=new ExternalToolManagerPrivate; + + // Getting dirs + d->mUserToolDir=KGlobal::dirs()->saveLocation("appdata", "tools"); + d->mUserToolDir=addSlash(d->mUserToolDir); + Q_ASSERT(!d->mUserToolDir.isEmpty()); + LOG("d->mUserToolDir:" << d->mUserToolDir); + + QStringList dirs=KGlobal::dirs()->findDirs("appdata", "tools"); + LOG("dirs:" << dirs.join(",")); + + // Loading desktop files + QDict systemDesktopFiles; + QStringList::ConstIterator it; + for (it=dirs.begin(); it!=dirs.end(); ++it) { + if (addSlash(*it)==d->mUserToolDir) { + LOG("skipping " << *it); + continue; + } + LOG("loading system desktop files from " << *it); + loadDesktopFiles(systemDesktopFiles, *it); + } + QDict userDesktopFiles; + loadDesktopFiles(userDesktopFiles, d->mUserToolDir); + + // Merge system and user desktop files into our KDesktopFile dictionary + d->mDesktopFiles=systemDesktopFiles; + d->mDesktopFiles.setAutoDelete(true); + QDictIterator itDict(userDesktopFiles); + + for (; itDict.current(); ++itDict) { + QString name=itDict.currentKey(); + KDesktopFile* df=itDict.current(); + if (d->mDesktopFiles.find(name)) { + d->mDesktopFiles.remove(name); + } + if (df->readBoolEntry("Hidden")) { + delete df; + } else { + d->mDesktopFiles.insert(name, df); + } + } + + d->mServices.setAutoDelete(true); + updateServices(); +} + + +ExternalToolManager::~ExternalToolManager() { + delete d; +} + + +ExternalToolManager* ExternalToolManager::instance() { + static ExternalToolManager manager; + return &manager; +} + + +void ExternalToolManager::updateServices() { + d->mServices.clear(); + QDictIterator it(d->mDesktopFiles); + for (; it.current(); ++it) { + KDesktopFile* desktopFile=it.current(); + // If sync() is not called, KService does not read up to date content + desktopFile->sync(); + KService* service=new KService(desktopFile); + d->mServices.append(service); + } +} + + +QDict& ExternalToolManager::desktopFiles() const { + return d->mDesktopFiles; +} + + +void ExternalToolManager::hideDesktopFile(KDesktopFile* desktopFile) { + QFileInfo fi(desktopFile->fileName()); + QString name=QString("%1.desktop").arg( fi.baseName(true) ); + d->mDesktopFiles.take(name); + + if (desktopFile->isReadOnly()) { + delete desktopFile; + desktopFile=new KDesktopFile(d->mUserToolDir + "/" + name, false); + } + desktopFile->writeEntry("Hidden", true); + desktopFile->sync(); + delete desktopFile; +} + + +KDesktopFile* ExternalToolManager::editSystemDesktopFile(const KDesktopFile* desktopFile) { + Q_ASSERT(desktopFile); + QFileInfo fi(desktopFile->fileName()); + + QString name=fi.baseName(true); + d->mDesktopFiles.remove(QString("%1.desktop").arg(name)); + + return createUserDesktopFile(name); +} + + +KDesktopFile* ExternalToolManager::createUserDesktopFile(const QString& name) { + Q_ASSERT(!name.isEmpty()); + KDesktopFile* desktopFile=new KDesktopFile( + d->mUserToolDir + "/" + name + ".desktop", false); + d->mDesktopFiles.insert(QString("%1.desktop").arg(name), desktopFile); + + return desktopFile; +} + + +ExternalToolContext* ExternalToolManager::createContext( + QObject* parent, const KFileItemList* items) +{ + KURL::List urls; + QStringList mimeTypes; + + // Create our URL list and a list of the different mime types present in + // the selection + QPtrListIterator it(*items); + for (; it.current(); ++it) { + urls.append(it.current()->url()); + QString mimeType=it.current()->mimetype(); + if (!mimeTypes.contains(mimeType)) { + mimeTypes.append(mimeType); + } + } + + return d->createContextInternal(parent, urls, mimeTypes); +} + + +ExternalToolContext* ExternalToolManager::createContext( + QObject* parent, const KURL& url) +{ + KURL::List urls; + QStringList mimeTypes; + + urls.append(url); + QString mimeType=KMimeType::findByURL(url, 0, url.isLocalFile(), true)->name(); + mimeTypes.append(mimeType); + + return d->createContextInternal(parent, urls, mimeTypes); +} + + +} // namespace diff --git a/src/gvcore/externaltoolmanager.h b/src/gvcore/externaltoolmanager.h new file mode 100644 index 0000000..8cf01ab --- /dev/null +++ b/src/gvcore/externaltoolmanager.h @@ -0,0 +1,67 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef EXTERNALTOOLMANAGER_H +#define EXTERNALTOOLMANAGER_H + +// Qt +#include +#include + +// KDE +#include + +// Local +#include "libgwenview_export.h" + +class KActionMenu; +class KURL; + +namespace Gwenview { +class ExternalToolContext; +class ExternalToolManagerPrivate; + +class LIBGWENVIEW_EXPORT ExternalToolManager { +public: + ~ExternalToolManager(); + + ExternalToolContext* createContext(QObject* parent, const KFileItemList*); + ExternalToolContext* createContext(QObject* parent, const KURL&); + + static ExternalToolManager* instance(); + QDict& desktopFiles() const; + + void hideDesktopFile(KDesktopFile*); + + // Create a new desktop file + KDesktopFile* createUserDesktopFile(const QString& name); + + // Create a desktop file based on a existing (system) desktop file + KDesktopFile* editSystemDesktopFile(const KDesktopFile* desktopFile); + void updateServices(); + +private: + ExternalToolManager(); + ExternalToolManagerPrivate* d; +}; + +} // namespace +#endif + diff --git a/src/gvcore/filedetailview.cpp b/src/gvcore/filedetailview.cpp new file mode 100644 index 0000000..b36a1dd --- /dev/null +++ b/src/gvcore/filedetailview.cpp @@ -0,0 +1,552 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* This file is based on kfiledetailview.cpp v1.43 from the KDE libs. Original + copyright follows. +*/ +/* This file is part of the KDE libraries + Copyright (C) 1997 Stephan Kulow + 2000, 2001 Carsten Pfeiffer + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +// Qt +#include +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "archive.h" +#include "dragpixmapgenerator.h" +#include "filedetailviewitem.h" +#include "filedetailview.moc" +#include "timeutils.h" +namespace Gwenview { + + +static QPixmap createShownItemPixmap(int size, const QColor& color) { + QPixmap pix(size, size); + pix.fill(Qt::red); + QPainter painter(&pix); + int margin = 2; + + QPointArray pa(3); + int arrowSize = size/2 - margin; + int center = size/2 - 1; + pa[0] = QPoint((size - arrowSize) / 2, center - arrowSize); + pa[1] = QPoint((size + arrowSize) / 2, center); + pa[2] = QPoint(pa[0].x(), center + arrowSize); + + painter.setBrush(color); + painter.setPen(color); + painter.drawPolygon(pa); + painter.end(); + + pix.setMask(pix.createHeuristicMask()); + + return pix; +} + + +FileDetailView::FileDetailView(QWidget *parent, const char *name) + : KListView(parent, name), FileViewBase() +{ + mSortingCol = COL_NAME; + mBlockSortingSignal = false; + + addColumn( i18n( "Name" ) ); + addColumn( i18n( "Size" ) ); + addColumn( i18n( "Date" ) ); + addColumn( i18n( "Permissions" ) ); + addColumn( i18n( "Owner" ) ); + addColumn( i18n( "Group" ) ); + setShowSortIndicator( TRUE ); + setAllColumnsShowFocus( TRUE ); + + connect( header(), SIGNAL( sectionClicked(int)), + SLOT(slotSortingChanged(int) )); + + + connect( this, SIGNAL( returnPressed(QListViewItem *) ), + SLOT( slotActivate( QListViewItem *) ) ); + + connect( this, SIGNAL( clicked(QListViewItem *, const QPoint&, int)), + SLOT( selected( QListViewItem *) ) ); + connect( this, SIGNAL( doubleClicked(QListViewItem *, const QPoint&, int)), + SLOT( slotActivate( QListViewItem *) ) ); + + connect( this, SIGNAL(contextMenuRequested( QListViewItem *, + const QPoint &, int )), + this, SLOT( slotActivateMenu( QListViewItem *, const QPoint& ))); + + QListView::setSelectionMode( QListView::Extended ); + connect( this, SIGNAL( selectionChanged() ), + SLOT( slotSelectionChanged() )); + + // FileViewStack need to be aware of sort changes, to update the sort menu + connect( sig, SIGNAL(sortingChanged(QDir::SortSpec)), + this, SIGNAL(sortingChanged(QDir::SortSpec)) ); + + setSorting( sorting() ); + + + mResolver = + new KMimeTypeResolver( this ); + + setDragEnabled(true); + + setAcceptDrops(true); + setDropVisualizer(false); + setDropHighlighter(false); + + int size = IconSize(KIcon::Small); + mShownItemUnselectedPixmap = createShownItemPixmap(size, colorGroup().highlight()); + mShownItemSelectedPixmap = createShownItemPixmap(size, colorGroup().highlightedText()); +} + + +FileDetailView::~FileDetailView() +{ + delete mResolver; +} + + +void FileDetailView::setSelected( const KFileItem *info, bool enable ) +{ + if (!info) return; + FileDetailViewItem *item = viewItem(info); + if (item) KListView::setSelected(item, enable); +} + +void FileDetailView::setCurrentItem( const KFileItem *item ) +{ + if (!item) return; + FileDetailViewItem *listItem = viewItem(item); + if (listItem) KListView::setCurrentItem(listItem); +} + +KFileItem * FileDetailView::currentFileItem() const +{ + FileDetailViewItem *current = static_cast( currentItem() ); + if ( current ) return current->fileInfo(); + + return 0L; +} + +void FileDetailView::clearSelection() +{ + KListView::clearSelection(); +} + +void FileDetailView::selectAll() +{ + KListView::selectAll( true ); +} + +void FileDetailView::invertSelection() +{ + KListView::invertSelection(); +} + +void FileDetailView::slotActivateMenu (QListViewItem *item,const QPoint& pos ) +{ + if ( !item ) { + sig->activateMenu( 0, pos ); + return; + } + FileDetailViewItem *i = (FileDetailViewItem*) item; + sig->activateMenu( i->fileInfo(), pos ); +} + +void FileDetailView::clearView() +{ + mResolver->m_lstPendingMimeIconItems.clear(); + mShownFileItem=0L; + KListView::clear(); +} + +void FileDetailView::insertItem( KFileItem *i ) +{ + KFileView::insertItem( i ); + + FileDetailViewItem *item = new FileDetailViewItem( (QListView*) this, i ); + + setSortingKey( item, i ); + + i->setExtraData( this, item ); + + if ( !i->isMimeTypeKnown() ) + mResolver->m_lstPendingMimeIconItems.append( item ); +} + +void FileDetailView::slotActivate( QListViewItem *item ) +{ + if ( !item ) return; + + const KFileItem *fi = ( (FileDetailViewItem*)item )->fileInfo(); + if ( fi ) sig->activate( fi ); +} + +void FileDetailView::selected( QListViewItem *item ) +{ + if ( !item ) return; + + if ( KGlobalSettings::singleClick() ) { + const KFileItem *fi = ( (FileDetailViewItem*)item )->fileInfo(); + if ( fi && (fi->isDir() || !onlyDoubleClickSelectsFiles()) ) + sig->activate( fi ); + } +} + +void FileDetailView::highlighted( QListViewItem *item ) +{ + if ( !item ) return; + + const KFileItem *fi = ( (FileDetailViewItem*)item )->fileInfo(); + if ( fi ) sig->highlightFile( fi ); +} + + +bool FileDetailView::isSelected(const KFileItem* fileItem) const +{ + if (!fileItem) return false; + + FileDetailViewItem *item = viewItem(fileItem); + return item && item->isSelected(); +} + + +void FileDetailView::updateView( bool b ) +{ + if ( !b ) return; + + QListViewItemIterator it( (QListView*)this ); + for ( ; it.current(); ++it ) { + FileDetailViewItem *item=static_cast(it.current()); + item->setPixmap( 0, item->fileInfo()->pixmap(KIcon::SizeSmall) ); + } +} + +void FileDetailView::updateView( const KFileItem *i ) +{ + if ( !i ) return; + + FileDetailViewItem *item = viewItem(i); + if ( !item ) return; + + item->init(); + setSortingKey( item, i ); +} + + +void FileDetailView::setSortingKey( FileDetailViewItem *dvItem, const KFileItem *item) +{ + QDir::SortSpec spec = KFileView::sorting(); + bool isDirOrArchive=item->isDir() || Archive::fileItemIsArchive(item); + + QString key; + if ( spec & QDir::Time ) { + time_t time = TimeUtils::getTime(item); + key=sortingKey(time, isDirOrArchive, spec); + + } else if ( spec & QDir::Size ) { + key=sortingKey( item->size(), isDirOrArchive, spec ); + + } else { + // Name or Unsorted + key=sortingKey( item->text(), isDirOrArchive, spec ); + } + + dvItem->setKey(key); +} + + +void FileDetailView::removeItem( const KFileItem *i ) +{ + if ( !i ) return; + + FileDetailViewItem *item = viewItem(i); + mResolver->m_lstPendingMimeIconItems.remove( item ); + if(mShownFileItem==i) mShownFileItem=0L; + delete item; + + KFileView::removeItem( i ); +} + +void FileDetailView::slotSortingChanged( int col ) +{ + QDir::SortSpec sort = sorting(); + int sortSpec = -1; + bool reversed = col == mSortingCol && (sort & QDir::Reversed) == 0; + mSortingCol = col; + + switch( col ) { + case COL_NAME: + sortSpec = (sort & ~QDir::SortByMask | QDir::Name); + break; + case COL_SIZE: + sortSpec = (sort & ~QDir::SortByMask | QDir::Size); + break; + case COL_DATE: + sortSpec = (sort & ~QDir::SortByMask | QDir::Time); + break; + + // the following columns have no equivalent in QDir, so we set it + // to QDir::Unsorted and remember the column (mSortingCol) + case COL_OWNER: + case COL_GROUP: + case COL_PERM: + // grmbl, QDir::Unsorted == SortByMask. + sortSpec = (sort & ~QDir::SortByMask);// | QDir::Unsorted; + break; + default: + break; + } + + if ( reversed ) + sortSpec |= QDir::Reversed; + else + sortSpec &= ~QDir::Reversed; + + if ( sort & QDir::IgnoreCase ) + sortSpec |= QDir::IgnoreCase; + else + sortSpec &= ~QDir::IgnoreCase; + + + KFileView::setSorting( static_cast( sortSpec ) ); + + KFileItem *item; + KFileItemListIterator it( *items() ); + + for ( ; (item = it.current() ); ++it ) { + FileDetailViewItem* thumbItem=viewItem( item ); + if (thumbItem) setSortingKey(thumbItem,item); + } + + KListView::setSorting( mSortingCol, !reversed ); + KListView::sort(); + + if (!mBlockSortingSignal) sig->changeSorting( static_cast( sortSpec ) ); +} + + +void FileDetailView::setSorting( QDir::SortSpec spec ) +{ + int col = 0; + if ( spec & QDir::Time ) + col = COL_DATE; + else if ( spec & QDir::Size ) + col = COL_SIZE; + else if ( spec & QDir::Unsorted ) + col = mSortingCol; + else + col = COL_NAME; + + // inversed, because slotSortingChanged will reverse it + if ( spec & QDir::Reversed ) + spec = (QDir::SortSpec) (spec & ~QDir::Reversed); + else + spec = (QDir::SortSpec) (spec | QDir::Reversed); + + mSortingCol = col; + KFileView::setSorting( (QDir::SortSpec) spec ); + + + // don't emit sortingChanged() when called via setSorting() + mBlockSortingSignal = true; // can't use blockSignals() + slotSortingChanged( col ); + mBlockSortingSignal = false; +} + +void FileDetailView::ensureItemVisible( const KFileItem *i ) +{ + if ( !i ) return; + + FileDetailViewItem *item = viewItem(i); + + if ( item ) KListView::ensureItemVisible( item ); +} + +// we're in multiselection mode +void FileDetailView::slotSelectionChanged() +{ + sig->highlightFile( 0L ); +} + +KFileItem * FileDetailView::firstFileItem() const +{ + FileDetailViewItem *item = static_cast( firstChild() ); + if ( item ) return item->fileInfo(); + return 0L; +} + +KFileItem * FileDetailView::nextItem( const KFileItem *fileItem ) const +{ + if ( fileItem ) { + FileDetailViewItem *item = viewItem( fileItem ); + if ( item && item->itemBelow() ) + return ((FileDetailViewItem*) item->itemBelow())->fileInfo(); + else + return 0L; + } + else + return firstFileItem(); +} + +KFileItem * FileDetailView::prevItem( const KFileItem *fileItem ) const +{ + if ( fileItem ) { + FileDetailViewItem *item = viewItem( fileItem ); + if ( item && item->itemAbove() ) + return ((FileDetailViewItem*) item->itemAbove())->fileInfo(); + else + return 0L; + } + else + return firstFileItem(); +} + +void FileDetailView::keyPressEvent( QKeyEvent *e ) +{ + KListView::keyPressEvent( e ); + + if ( e->key() == Key_Return || e->key() == Key_Enter ) { + if ( e->state() & ControlButton ) + e->ignore(); + else + e->accept(); + } +} + +// +// mimetype determination on demand +// +void FileDetailView::mimeTypeDeterminationFinished() +{ + // anything to do? +} + +void FileDetailView::determineIcon( FileDetailViewItem *item ) +{ + (void) item->fileInfo()->determineMimeType(); + updateView( item->fileInfo() ); +} + +void FileDetailView::listingCompleted() +{ + mResolver->start(); +} + +void FileDetailView::startDrag() +{ + /** + * The item drawer for DragPixmapGenerator + */ + struct ItemDrawer : public DragPixmapItemDrawer { + ItemDrawer(const QFontMetrics& fontMetrics) + : mFontMetrics(fontMetrics) {} + + QSize itemSize(KFileItem* fileItem) { + if (!fileItem) return QSize(); + QString name = fileItem->name(); + int width = QMIN(mGenerator->maxWidth(), mFontMetrics.width(name)); + int height = mFontMetrics.height(); + return QSize(width, height); + } + + void drawItem(QPainter* painter, int left, int top, KFileItem* fileItem) { + QString name = fileItem->name(); + painter->save(); + KWordWrap::drawFadeoutText(painter, + left, top + mFontMetrics.ascent(), + mGenerator->maxWidth(), name); + painter->restore(); + } + + QFontMetrics mFontMetrics; + }; + ItemDrawer drawer(fontMetrics()); + + + KURL::List urls; + KFileItemListIterator it(*KFileView::selectedItems()); + + DragPixmapGenerator generator; + generator.setItemDrawer(&drawer); + + for ( ; it.current(); ++it ) { + urls.append(it.current()->url()); + generator.addItem(it.current()); + } + + if (urls.isEmpty()) { + kdWarning() << "No item to drag\n"; + return; + } + + QDragObject* drag=new KURLDrag(urls, this, 0); + QPixmap dragPixmap = generator.generate(); + + drag->setPixmap( dragPixmap, QPoint(-generator.DRAG_OFFSET, -generator.DRAG_OFFSET)); + drag->dragCopy(); +} + + +void FileDetailView::setShownFileItem(KFileItem* fileItem) +{ + if( fileItem == mShownFileItem ) return; + FileDetailViewItem* oldShownItem=viewItem(mShownFileItem); + FileDetailViewItem* newShownItem=viewItem(fileItem); + + FileViewBase::setShownFileItem(fileItem); + if (oldShownItem) oldShownItem->repaint(); + if (newShownItem) newShownItem->repaint(); +} + + +//---------------------------------------------------------------------- +// +// Drop support +// +//---------------------------------------------------------------------- +bool FileDetailView::acceptDrag(QDropEvent* event) const { + return KURLDrag::canDecode(event); +} + +void FileDetailView::contentsDropEvent(QDropEvent *event) { + KFileItem* fileItem=0L; + QListViewItem *item=itemAt(contentsToViewport(event->pos() ) ); + + if (item) { + fileItem=static_cast(item)->fileInfo(); + } + emit dropped(event,fileItem); +} + +} // namespace diff --git a/src/gvcore/filedetailview.h b/src/gvcore/filedetailview.h new file mode 100644 index 0000000..12313f6 --- /dev/null +++ b/src/gvcore/filedetailview.h @@ -0,0 +1,133 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* This file is based on kfiledetailview.h v1.30 from the KDE libs. Original + copyright follows. +*/ +/* This file is part of the KDE libraries + Copyright (C) 1997 Stephan Kulow + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef FILEDETAILVIEW_H +#define FILEDETAILVIEW_H + +class KFileItem; +class QWidget; +class QKeyEvent; + +// Qt includes +#include + +// KDE includes +#include +#include + +// Our includes +#include "fileviewbase.h" +namespace Gwenview { + +class FileDetailViewItem; + +class FileDetailView : public KListView, public FileViewBase +{ + Q_OBJECT + + friend class FileDetailViewItem; + +public: + FileDetailView(QWidget* parent, const char* name); + virtual ~FileDetailView(); + + virtual QWidget* widget() { return this; } + virtual void clearView(); + + virtual void updateView( bool ); + virtual void updateView(const KFileItem*); + virtual void removeItem( const KFileItem* ); + virtual void listingCompleted(); + + virtual void setSelected(const KFileItem* , bool); + virtual bool isSelected(const KFileItem* i) const; + virtual void clearSelection(); + virtual void selectAll(); + virtual void invertSelection(); + + virtual void setCurrentItem( const KFileItem* ); + virtual KFileItem* currentFileItem() const; + virtual KFileItem* firstFileItem() const; + virtual KFileItem* nextItem( const KFileItem* ) const; + virtual KFileItem* prevItem( const KFileItem* ) const; + + virtual void insertItem( KFileItem* i ); + + // implemented to get noticed about sorting changes (for sortingIndicator) + virtual void setSorting( QDir::SortSpec ); + + void ensureItemVisible( const KFileItem* ); + + // for KMimeTypeResolver + void mimeTypeDeterminationFinished(); + void determineIcon( FileDetailViewItem* item ); + QScrollView* scrollWidget() { return this; } + + void setShownFileItem(KFileItem* fileItem); + +signals: + void dropped(QDropEvent* event, KFileItem* item); + void sortingChanged(QDir::SortSpec); + +protected: + virtual bool acceptDrag(QDropEvent*) const; + virtual void contentsDropEvent(QDropEvent*); + virtual void keyPressEvent(QKeyEvent*); + + int mSortingCol; + +protected slots: + void slotSelectionChanged(); + +private slots: + void slotSortingChanged( int ); + void selected( QListViewItem* item ); + void slotActivate( QListViewItem* item ); + void highlighted( QListViewItem* item ); + void slotActivateMenu ( QListViewItem* item, const QPoint& pos ); + +private: + bool mBlockSortingSignal; + KMimeTypeResolver* mResolver; + + virtual void insertItem(QListViewItem* i) { KListView::insertItem(i); } + virtual void setSorting(int i, bool b) { KListView::setSorting(i, b); } + virtual void setSelected(QListViewItem* i, bool b) { KListView::setSelected(i, b); } + + FileDetailViewItem* viewItem( const KFileItem* item ) const { + if (item) return (FileDetailViewItem*)item->extraData(this); + return 0L; + } + + void setSortingKey(FileDetailViewItem* item, const KFileItem* i); + + void startDrag(); + + QPixmap mShownItemSelectedPixmap; + QPixmap mShownItemUnselectedPixmap; +}; + + +} // namespace +#endif + diff --git a/src/gvcore/filedetailviewitem.cpp b/src/gvcore/filedetailviewitem.cpp new file mode 100644 index 0000000..d02427d --- /dev/null +++ b/src/gvcore/filedetailviewitem.cpp @@ -0,0 +1,70 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* This file is based on kfiledetailview.cpp from the KDE libs. Original + copyright follows. +*/ +/* This file is part of the KDE libraries + Copyright (C) 1997 Stephan Kulow + 2000, 2001 Carsten Pfeiffer + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +// KDE includes +#include +#include + +// Our includes +#include "filedetailviewitem.h" +#include "filedetailview.h" +#include "timeutils.h" +namespace Gwenview { + + +void FileDetailViewItem::init() +{ + time_t time = TimeUtils::getTime(inf); + setPixmap( COL_NAME, inf->pixmap(KIcon::SizeSmall)); + + setText( COL_NAME, inf->text() ); + setText( COL_SIZE, KGlobal::locale()->formatNumber( inf->size(), 0)); + setText( COL_DATE, TimeUtils::formatTime(time) ); + setText( COL_PERM, inf->permissionsString() ); + setText( COL_OWNER, inf->user() ); + setText( COL_GROUP, inf->group() ); +} + + +const QPixmap* FileDetailViewItem::pixmap(int column) const { + const QPixmap* normalPix = KListViewItem::pixmap(column); + if (column!=0) { + return normalPix; + } + + FileDetailView* view=static_cast(listView()); + FileDetailViewItem* viewedItem=view->viewItem(view->shownFileItem()); + if (viewedItem!=this) { + return normalPix; + } + + if (isSelected()) { + return &view->mShownItemSelectedPixmap; + } else { + return &view->mShownItemUnselectedPixmap; + } +} + + +} // namespace diff --git a/src/gvcore/filedetailviewitem.h b/src/gvcore/filedetailviewitem.h new file mode 100644 index 0000000..2e4c8ff --- /dev/null +++ b/src/gvcore/filedetailviewitem.h @@ -0,0 +1,89 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* This file is based on kfiledetailview.h from the KDE libs. Original + copyright follows. +*/ +/* This file is part of the KDE libraries + Copyright (C) 1997 Stephan Kulow + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef FILEDETAILVIEWITEM_H +#define FILEDETAILVIEWITEM_H + +// KDE includes +#include +#include +namespace Gwenview { + +#define COL_NAME 0 +#define COL_SIZE 1 +#define COL_DATE 2 +#define COL_PERM 3 +#define COL_OWNER 4 +#define COL_GROUP 5 + +class FileDetailViewItem : public KListViewItem +{ +public: + FileDetailViewItem( QListView* parent, const QString &text, + const QPixmap &icon, KFileItem* fi ) + : KListViewItem( parent, text ), inf( fi ) { + setPixmap( 0, icon ); + setText( 0, text ); + } + + FileDetailViewItem( QListView* parent, KFileItem* fi ) + : KListViewItem( parent ), inf( fi ) { + init(); + } + + FileDetailViewItem( QListView* parent, const QString &text, + const QPixmap &icon, KFileItem* fi, + QListViewItem* after) + : KListViewItem( parent, after ), inf( fi ) { + setPixmap( 0, icon ); + setText( 0, text ); + } + + ~FileDetailViewItem() { + inf->removeExtraData( listView() ); + } + + KFileItem* fileInfo() const { return inf; } + + virtual QString key( int /*column*/, bool /*ascending*/ ) const { return m_key; } + + void setKey( const QString& key ) { m_key = key; } + + QRect rect() const + { + QRect r = listView()->itemRect(this); + return QRect( listView()->viewportToContents( r.topLeft() ), + QSize( r.width(), r.height() ) ); + } + + void init(); + virtual const QPixmap* pixmap(int column) const; + +private: + KFileItem* inf; + QString m_key; +}; + +} // namespace +#endif + diff --git a/src/gvcore/fileoperation.cpp b/src/gvcore/fileoperation.cpp new file mode 100644 index 0000000..99b015b --- /dev/null +++ b/src/gvcore/fileoperation.cpp @@ -0,0 +1,119 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Self +#include "fileoperation.moc" + +// Qt +#include +#include +#include + +// KDE +#include +#include +#include + +// Local +#include "fileopobject.h" +#include "fileoperationconfig.h" + +namespace Gwenview { + + +namespace FileOperation { + +void copyTo(const KURL::List& srcURL,QWidget* parent) { + FileOpObject* op=new FileOpCopyToObject(srcURL,parent); + (*op)(); +} + +void linkTo(const KURL::List& srcURL,QWidget* parent) { + FileOpObject* op=new FileOpLinkToObject(srcURL,parent); + (*op)(); +} + +void moveTo(const KURL::List& srcURL,QWidget* parent,QObject* receiver,const char* slot) { + FileOpObject* op=new FileOpMoveToObject(srcURL,parent); + if (receiver && slot) QObject::connect(op,SIGNAL(success()),receiver,slot); + (*op)(); +} + +void makeDir(const KURL& parentURL, QWidget* parent, QObject* receiver, const char* slot) { + FileOpObject* op=new FileOpMakeDirObject(parentURL, parent); + if (receiver && slot) QObject::connect(op,SIGNAL(success()),receiver,slot); + (*op)(); +} + +void del(const KURL::List& url,QWidget* parent,QObject* receiver,const char* slot) { + FileOpObject* op = new FileOpDelObject(url,parent); + if (receiver && slot) QObject::connect(op,SIGNAL(success()),receiver,slot); + (*op)(); +} + + +void trash(const KURL::List& url, QWidget* parent, QObject* receiver, const char* slot) { + FileOpObject* op = new FileOpTrashObject(url,parent); + if (receiver && slot) QObject::connect(op,SIGNAL(success()),receiver,slot); + (*op)(); +} + + +void realDelete(const KURL::List& url, QWidget* parent, QObject* receiver, const char* slot) { + FileOpObject* op = new FileOpRealDeleteObject(url,parent); + if (receiver && slot) QObject::connect(op,SIGNAL(success()),receiver,slot); + (*op)(); +} + + +void rename(const KURL& url,QWidget* parent,QObject* receiver,const char* slot) { + FileOpObject* op=new FileOpRenameObject(url,parent); + if (receiver && slot) QObject::connect(op,SIGNAL(renamed(const QString&)),receiver,slot); + (*op)(); +} + + +void fillDropURLMenu(QPopupMenu* menu, const KURL::List& urls, const KURL& target, bool* wasMoved) { + DropMenuContext* context=new DropMenuContext(menu, urls, target, wasMoved); + menu->insertItem( SmallIcon("goto"), i18n("&Move Here"), + context, SLOT(move()) ); + menu->insertItem( SmallIcon("editcopy"), i18n("&Copy Here"), + context, SLOT(copy()) ); + menu->insertItem( SmallIcon("www"), i18n("&Link Here"), + context, SLOT(link()) ); +} + + +void openDropURLMenu(QWidget* parent, const KURL::List& urls, const KURL& target, bool* wasMoved) { + QPopupMenu menu(parent); + if (wasMoved) *wasMoved=false; + + fillDropURLMenu(&menu, urls, target, wasMoved); + menu.insertSeparator(); + menu.insertItem( SmallIcon("cancel"), i18n("Cancel") ); + + menu.setMouseTracking(true); + menu.exec(QCursor::pos()); +} + + +} // namespace FileOperation + +} // namespace diff --git a/src/gvcore/fileoperation.h b/src/gvcore/fileoperation.h new file mode 100644 index 0000000..bb71ed6 --- /dev/null +++ b/src/gvcore/fileoperation.h @@ -0,0 +1,95 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef FILEOPERATION_H +#define FILEOPERATION_H + +// KDE +#include +#include + +#include "libgwenview_export.h" + +class QPopupMenu; +class QWidget; + +namespace Gwenview { +/** + * This namespace handles all steps of a file operation : + * - asking the user what to do with a file + * - performing the operation + * - showing result dialogs + */ +namespace FileOperation { + +LIBGWENVIEW_EXPORT void copyTo(const KURL::List&,QWidget* parent=0L); +LIBGWENVIEW_EXPORT void moveTo(const KURL::List&,QWidget* parent,QObject* receiver=0L,const char* slot=0L); +LIBGWENVIEW_EXPORT void linkTo(const KURL::List& srcURL,QWidget* parent); +LIBGWENVIEW_EXPORT void makeDir(const KURL& parentURL, QWidget* parent, QObject* receiver=0L, const char* slot=0L); +LIBGWENVIEW_EXPORT void del(const KURL::List&,QWidget* parent,QObject* receiver=0L,const char* slot=0L); +LIBGWENVIEW_EXPORT void trash(const KURL::List&,QWidget* parent,QObject* receiver=0L,const char* slot=0L); +LIBGWENVIEW_EXPORT void realDelete(const KURL::List&,QWidget* parent,QObject* receiver=0L,const char* slot=0L); +LIBGWENVIEW_EXPORT void rename(const KURL&,QWidget* parent,QObject* receiver=0L,const char* slot=0L); + + +/** + * @internal + */ +class DropMenuContext : public QObject { +Q_OBJECT +public: + DropMenuContext(QObject* parent, const KURL::List& src, const KURL& dst, bool* wasMoved) + : QObject(parent) + , mSrc(src) + , mDst(dst) + , mWasMoved(wasMoved) + { + if (mWasMoved) *mWasMoved=false; + } + +public slots: + void copy() { + KIO::copy(mSrc, mDst, true); + } + + void move() { + KIO::move(mSrc, mDst, true); + if (mWasMoved) *mWasMoved=true; + } + + void link() { + KIO::link(mSrc, mDst, true); + } + +private: + KURL::List mSrc; + KURL mDst; + bool* mWasMoved; +}; + + +LIBGWENVIEW_EXPORT void fillDropURLMenu(QPopupMenu*, const KURL::List&, const KURL& target, bool* wasMoved=0L); +LIBGWENVIEW_EXPORT void openDropURLMenu(QWidget* parent, const KURL::List&, const KURL& target, bool* wasMoved=0L); + +} // namespace + +} // namespace +#endif + diff --git a/src/gvcore/fileoperationconfig.kcfg b/src/gvcore/fileoperationconfig.kcfg new file mode 100644 index 0000000..c876396 --- /dev/null +++ b/src/gvcore/fileoperationconfig.kcfg @@ -0,0 +1,22 @@ + + + + + + + true + + + true + + + true + + + true + + + + + + diff --git a/src/gvcore/fileoperationconfig.kcfgc b/src/gvcore/fileoperationconfig.kcfgc new file mode 100644 index 0000000..1b236c8 --- /dev/null +++ b/src/gvcore/fileoperationconfig.kcfgc @@ -0,0 +1,7 @@ +File=fileoperationconfig.kcfg +ClassName=FileOperationConfig +NameSpace=Gwenview +Singleton=true +Mutators=true +IncludeFiles=gvcore/libgwenview_export.h +Visibility=LIBGWENVIEW_EXPORT diff --git a/src/gvcore/fileopobject.cpp b/src/gvcore/fileopobject.cpp new file mode 100644 index 0000000..c480156 --- /dev/null +++ b/src/gvcore/fileopobject.cpp @@ -0,0 +1,347 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// Qt +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "deletedialog.h" +#include "fileoperation.h" +#include "fileopobject.moc" +#include "fileoperationconfig.h" +#include "inputdialog.h" +namespace Gwenview { + + +/** + * A tweaked KFileDialog used to select an existing directory. More efficient + * than KDirSelectDialog, since it provides access to bookmarks and let you + * create a dir. + */ +class DirSelectDialog : public KFileDialog { +public: + DirSelectDialog(const QString& startDir, QWidget* parent) + : KFileDialog(startDir, QString::null, parent, "dirselectdialog", true) { + locationEdit->setEnabled(false); + filterWidget->setEnabled(false); + setMode(KFile::Directory | KFile::ExistingOnly); + + // Cast to avoid gcc being confused + setPreviewWidget(static_cast(0)); + } +}; + + +//-FileOpObject-------------------------------------------------------------------- +FileOpObject::FileOpObject(const KURL& url,QWidget* parent) +: mParent(parent) +{ + mURLList.append(url); +} + + +FileOpObject::FileOpObject(const KURL::List& list,QWidget* parent) +: mParent(parent), mURLList(list) +{} + + +void FileOpObject::slotResult(KIO::Job* job) { + if (job->error()) { + job->showErrorDialog(mParent); + } + + emit success(); + +// Let's shoot ourself in the foot... + delete this; +} + + +void FileOpObject::polishJob(KIO::Job* job) { + job->setWindow(mParent->topLevelWidget()); + connect( job, SIGNAL( result(KIO::Job*) ), + this, SLOT( slotResult(KIO::Job*) ) ); +} + + +//-FileOpCopyToObject-------------------------------------------------------------- + + +void FileOpCopyToObject::operator()() { + KURL destURL; + + if (FileOperationConfig::confirmCopy()) { + QString destDir = FileOperationConfig::destDir(); + if( !destDir.isEmpty()) { + destDir += "/"; + } + if (mURLList.size()==1) { + destURL=KFileDialog::getSaveURL(destDir + mURLList.first().fileName(), + QString::null, mParent, i18n("Copy File")); + } else { + DirSelectDialog dialog(destDir, mParent); + dialog.setCaption(i18n("Select Folder Where Files Will be Copied")); + dialog.exec(); + destURL=dialog.selectedURL(); + } + } else { + destURL.setPath(FileOperationConfig::destDir()); + } + if (destURL.isEmpty()) return; + +// Copy the file + KIO::Job* job=KIO::copy(mURLList,destURL,true); + polishJob(job); + +} + + +//-FileOpCopyToObject-------------------------------------------------------------- + + +void FileOpLinkToObject::operator()() { + KURL destURL; + + if (FileOperationConfig::confirmCopy()) { + QString destDir = FileOperationConfig::destDir(); + if( !destDir.isEmpty()) { + destDir += "/"; + } + if (mURLList.size()==1) { + destURL=KFileDialog::getSaveURL(destDir + mURLList.first().fileName(), + QString::null, mParent, i18n("Link File")); + } else { + DirSelectDialog dialog(destDir, mParent); + dialog.setCaption(i18n("Select Folder Where the Files Will be Linked")); + dialog.exec(); + destURL=dialog.selectedURL(); + } + } else { + destURL.setPath(FileOperationConfig::destDir()); + } + if (destURL.isEmpty()) return; + +// Copy the file + KIO::Job* job=KIO::link(mURLList,destURL,true); + polishJob(job); +} + + +//-FileOpMoveToObject-------------------------------------------------------------- +void FileOpMoveToObject::operator()() { + KURL destURL; + + if (FileOperationConfig::confirmMove()) { + QString destDir = FileOperationConfig::destDir(); + if( !destDir.isEmpty()) { + destDir += "/"; + } + if (mURLList.size()==1) { + destURL=KFileDialog::getSaveURL(destDir + mURLList.first().fileName(), + QString::null, mParent, i18n("Move File")); + } else { + DirSelectDialog dialog(destDir, mParent); + dialog.setCaption(i18n("Select Folder Where Files Will be Moved")); + dialog.exec(); + destURL=dialog.selectedURL(); + } + } else { + destURL.setPath(FileOperationConfig::destDir()); + } + if (destURL.isEmpty()) return; + +// Move the file + KIO::Job* job=KIO::move(mURLList,destURL,true); + polishJob(job); +} + + +//-FileOpMakeDirObject------------------------------------------------------------- +void FileOpMakeDirObject::operator()() { + InputDialog dlg(mParent); + dlg.setCaption( i18n("Creating Folder") ); + dlg.setLabel( i18n("Enter the name of the new folder:") ); + dlg.setButtonOK( KGuiItem(i18n("Create Folder"), "folder_new") ); + if (!dlg.exec()) return; + + QString newDir = dlg.lineEdit()->text(); + + KURL newURL(mURLList.first()); + newURL.addPath(newDir); + KIO::Job* job=KIO::mkdir(newURL); + polishJob(job); +} + + +static KIO::Job* createTrashJob(KURL::List lst) { + KURL trashURL("trash:/"); + // Go do it + if (lst.count()==1) { + // If there's only one file, KIO::move will think we want to overwrite + // the trash dir with the file to trash, so we add the file name + trashURL.addPath(lst.first().fileName()); + } + return KIO::move(lst, trashURL); +} + +static KIO::Job* createDeleteJob(KURL::List lst) { + return KIO::del(lst, false, true); +} + + +//-FileOpDelObject----------------------------------------------------------------- +void FileOpDelObject::operator()() { + bool shouldDelete; + if (FileOperationConfig::confirmDelete()) { + DeleteDialog dlg(mParent); + dlg.setURLList(mURLList); + if (!dlg.exec()) return; + shouldDelete = dlg.shouldDelete(); + } else { + shouldDelete = not FileOperationConfig::deleteToTrash(); + } + + + KIO::Job* job; + if (shouldDelete) { + job = createDeleteJob(mURLList); + } else { + job = createTrashJob(mURLList); + } + polishJob(job); +} + + +//-FileOpTrashObject--------------------------------------------------------------- +void FileOpTrashObject::operator()() { + // Confirm operation + if (FileOperationConfig::confirmDelete()) { + int response; + if (mURLList.count()>1) { + QStringList fileList; + KURL::List::ConstIterator it=mURLList.begin(); + for (; it!=mURLList.end(); ++it) { + fileList.append((*it).filename()); + } + response=KMessageBox::warningContinueCancelList(mParent, + i18n("Do you really want to trash these files?"),fileList,i18n("Trash used as a verb", "Trash Files"),KGuiItem(i18n("Trash used as a verb", "&Trash"),"edittrash")); + } else { + QString filename=QStyleSheet::escape(mURLList.first().filename()); + response=KMessageBox::warningContinueCancel(mParent, + i18n("

Do you really want to move %1 to the trash?

").arg(filename),i18n("Trash used as a verb", "Trash File"),KGuiItem(i18n("Trash used as a verb", "&Trash"),"edittrash")); + } + if (response!=KMessageBox::Continue) return; + } + + KIO::Job* job = createTrashJob(mURLList); + polishJob(job); +} + +//-FileOpRealDeleteObject---------------------------------------------------------- +void FileOpRealDeleteObject::operator()() { + // Confirm operation + if (FileOperationConfig::confirmDelete()) { + int response; + if (mURLList.count()>1) { + QStringList fileList; + KURL::List::ConstIterator it=mURLList.begin(); + for (; it!=mURLList.end(); ++it) { + fileList.append((*it).filename()); + } + response=KMessageBox::warningContinueCancelList(mParent, + i18n("Do you really want to delete these files?"),fileList, + i18n("Delete Files"), + KStdGuiItem::del() + ); + } else { + QString filename=QStyleSheet::escape(mURLList.first().filename()); + response=KMessageBox::warningContinueCancel(mParent, + i18n("

Do you really want to delete %1?

").arg(filename), + i18n("Delete File"), + KStdGuiItem::del() + ); + } + if (response!=KMessageBox::Continue) return; + } + + // Delete the file + KIO::Job* job = createDeleteJob(mURLList); + polishJob(job); +} + + +//-FileOpRenameObject-------------------------------------------------------------- +void FileOpRenameObject::operator()() { + KURL srcURL=mURLList.first(); + + // Prompt for the new filename + QString filename = srcURL.filename(); + InputDialog dlg(mParent); + dlg.setCaption(i18n("Renaming File")); + dlg.setLabel(i18n("

Rename file %1 to:

").arg(QStyleSheet::escape(filename))); + dlg.setButtonOK( KGuiItem(i18n("&Rename"), "edit") ); + + dlg.lineEdit()->setText(filename); + int extPos = filename.findRev('.'); + if (extPos != -1) { + if (filename.mid(extPos - 4, 4) == ".tar") { + // Special case: *.tar.* + extPos -= 4; + } + dlg.lineEdit()->setSelection(0, extPos); + } + if (!dlg.exec()) return; + mNewFilename = dlg.lineEdit()->text(); + + // Rename the file + KURL destURL=srcURL; + destURL.setFileName(mNewFilename); + KIO::Job* job=KIO::move(srcURL,destURL); + polishJob(job); +} + + +void FileOpRenameObject::slotResult(KIO::Job* job) { + if (job->error()) { + job->showErrorDialog(mParent); + } + + emit success(); + emit renamed(mNewFilename); + +// Let's shoot ourself in the foot... + delete this; +} + +} // namespace diff --git a/src/gvcore/fileopobject.h b/src/gvcore/fileopobject.h new file mode 100644 index 0000000..d26f763 --- /dev/null +++ b/src/gvcore/fileopobject.h @@ -0,0 +1,143 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef FILEOPOBJECT_H +#define FILEOPOBJECT_H + +// Qt includes +#include +#include + +// KDE includes +#include +#include + +class QWidget; + + +namespace Gwenview { +/** + * This class is a base class for wrappers to KIO slaves asynchronous + * file operations. These classes handle all steps of a file operation : + * - asking the user what to do with a file + * - performing the operation + * - showing result dialogs + * + * All these classes are used by the @FileOperation namespace-like class + */ +class FileOpObject : public QObject { +Q_OBJECT +public: + FileOpObject(const KURL&,QWidget* parent=0L); + FileOpObject(const KURL::List&,QWidget* parent=0L); + virtual void operator()()=0; + +signals: + void success(); + +protected slots: + virtual void slotResult(KIO::Job*); + +protected: + QWidget* mParent; + KURL::List mURLList; + + void polishJob(KIO::Job*); +}; + + +class FileOpCopyToObject : public FileOpObject { +Q_OBJECT +public: + FileOpCopyToObject(const KURL& url,QWidget* parent=0L) : FileOpObject(url,parent) {} + FileOpCopyToObject(const KURL::List& urlList,QWidget* parent=0L) : FileOpObject(urlList,parent) {} + void operator()(); +}; + +class FileOpLinkToObject : public FileOpObject { +Q_OBJECT +public: + FileOpLinkToObject(const KURL& url,QWidget* parent=0L) : FileOpObject(url,parent) {} + FileOpLinkToObject(const KURL::List& urlList,QWidget* parent=0L) : FileOpObject(urlList,parent) {} + void operator()(); +}; + +class FileOpMoveToObject : public FileOpObject { +Q_OBJECT +public: + FileOpMoveToObject(const KURL& url,QWidget* parent=0L) : FileOpObject(url,parent) {} + FileOpMoveToObject(const KURL::List& urlList,QWidget* parent=0L) : FileOpObject(urlList,parent) {} + void operator()(); +}; + +class FileOpMakeDirObject : public FileOpObject { +Q_OBJECT +public: + FileOpMakeDirObject(const KURL& url, QWidget* parent=0L) : FileOpObject(url, parent) {} + void operator()(); +}; + +class FileOpDelObject : public FileOpObject { +Q_OBJECT +public: + FileOpDelObject(const KURL& url,QWidget* parent=0L) : FileOpObject(url,parent) {} + FileOpDelObject(const KURL::List& urlList,QWidget* parent=0L) : FileOpObject(urlList,parent) {} + void operator()(); +}; + + +class FileOpTrashObject : public FileOpObject { +Q_OBJECT +public: + FileOpTrashObject(const KURL& url,QWidget* parent=0L) : FileOpObject(url,parent) {} + FileOpTrashObject(const KURL::List& urlList,QWidget* parent=0L) : FileOpObject(urlList,parent) {} + void operator()(); +}; + + +class FileOpRealDeleteObject : public FileOpObject { +Q_OBJECT +public: + FileOpRealDeleteObject(const KURL& url,QWidget* parent=0L) : FileOpObject(url,parent) {} + FileOpRealDeleteObject(const KURL::List& urlList,QWidget* parent=0L) : FileOpObject(urlList,parent) {} + void operator()(); +}; + + +class FileOpRenameObject : public FileOpObject { +Q_OBJECT +public: + FileOpRenameObject(const KURL& url,QWidget* parent=0L) : FileOpObject(url,parent) {} + void operator()(); + +signals: + void renamed(const QString& newName); + +protected slots: + virtual void slotResult(KIO::Job*); + +private: + QString mNewFilename; +}; + + +} // namespace +#endif + diff --git a/src/gvcore/filethumbnailview.cpp b/src/gvcore/filethumbnailview.cpp new file mode 100644 index 0000000..d9d3ca2 --- /dev/null +++ b/src/gvcore/filethumbnailview.cpp @@ -0,0 +1,866 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// Qt +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "fileviewconfig.h" +#include "filethumbnailviewitem.h" +#include "archive.h" +#include "dragpixmapgenerator.h" +#include "thumbnailloadjob.h" +#include "busylevelmanager.h" +#include "imageloader.h" +#include "timeutils.h" +#include "thumbnailsize.h" +#include "thumbnaildetailsdialog.h" + +#undef ENABLE_LOG +#undef LOG +#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +#include "filethumbnailview.moc" +namespace Gwenview { + +static const int THUMBNAIL_UPDATE_DELAY=500; + +static const int RIGHT_TEXT_WIDTH=128; +static const int BOTTOM_MIN_TEXT_WIDTH=96; + +class ProgressWidget : public QFrame { + KProgress* mProgressBar; + QPushButton* mStop; +public: + ProgressWidget(FileThumbnailView* view, int count) + : QFrame(view) + { + QHBoxLayout* layout=new QHBoxLayout(this, 3, 3); + layout->setAutoAdd(true); + setFrameStyle( QFrame::StyledPanel | QFrame::Raised ); + + mStop=new QPushButton(this); + mStop->setPixmap(SmallIcon("stop")); + mStop->setFlat(true); + + mProgressBar=new KProgress(count, this); + mProgressBar->setFormat("%v/%m"); + + view->clipper()->installEventFilter(this); + } + + void polish() { + QFrame::polish(); + setMinimumWidth(layout()->minimumSize().width()); + //setFixedHeight( mProgressBar->height() ); + setFixedHeight( mStop->height() ); + } + + void showEvent(QShowEvent*) { + updatePosition(); + } + + bool eventFilter(QObject*, QEvent* event) { + if (event->type()==QEvent::Resize) { + updatePosition(); + } + return false; + } + + void updatePosition() { + FileThumbnailView* view=static_cast(parent()); + QSize tmp=view->clipper()->size() - size(); + move(tmp.width() - 2, tmp.height() - 2); + } + + KProgress* progressBar() const { return mProgressBar; } + QPushButton* stopButton() const { return mStop; } +}; + + +struct FileThumbnailView::Private { + int mThumbnailSize; + int mMarginSize; + bool mUpdateThumbnailsOnNextShow; + QPixmap mWaitPixmap; // The wait pixmap (32 x 32) + QPixmap mWaitThumbnail; // The wait thumbnail (mThumbnailSize x mThumbnailSize) + ProgressWidget* mProgressWidget; + + QGuardedPtr mThumbnailLoadJob; + + QTimer* mThumbnailUpdateTimer; + + int mItemDetails; + + ImageLoader* mPrefetch; + ThumbnailDetailsDialog* mThumbnailsDetailDialog; + + void updateWaitThumbnail(const FileThumbnailView* view) { + mWaitThumbnail=QPixmap(mThumbnailSize, mThumbnailSize); + mWaitThumbnail.fill(view->paletteBackgroundColor()); + QPainter painter(&mWaitThumbnail); + + painter.setPen(view->colorGroup().button()); + painter.drawRect(0,0,mThumbnailSize,mThumbnailSize); + painter.drawPixmap( + (mThumbnailSize-mWaitPixmap.width())/2, + (mThumbnailSize-mWaitPixmap.height())/2, + mWaitPixmap); + painter.end(); + } +}; + + +static FileThumbnailViewItem* viewItem(const FileThumbnailView* view, const KFileItem* fileItem) { + if (!fileItem) return 0L; + return static_cast( const_cast(fileItem->extraData(view) ) ); +} + + +FileThumbnailView::FileThumbnailView(QWidget* parent) +: KIconView(parent), FileViewBase() +{ + d=new Private; + d->mUpdateThumbnailsOnNextShow=false; + d->mThumbnailLoadJob=0L; + d->mWaitPixmap=QPixmap(::locate("appdata", "thumbnail/wait.png")); + d->mProgressWidget=0L; + d->mThumbnailUpdateTimer=new QTimer(this); + d->mMarginSize=FileViewConfig::thumbnailMarginSize(); + d->mItemDetails=FileViewConfig::thumbnailDetails(); + d->mPrefetch = NULL; + d->mThumbnailSize = 0; + d->mThumbnailsDetailDialog = 0; + + setItemTextPos( QIconView::ItemTextPos(FileViewConfig::thumbnailTextPos()) ); + setAutoArrange(true); + QIconView::setSorting(true); + setItemsMovable(false); + setResizeMode(Adjust); + setShowToolTips(true); + setSpacing(0); + setAcceptDrops(true); + + // We can't use KIconView::Execute mode because in this mode the current + // item is unselected after being clicked, so we use KIconView::Select mode + // and emit the execute() signal with slotClicked() ourself. + setMode(KIconView::Select); + connect(this, SIGNAL(clicked(QIconViewItem*)), + this, SLOT(slotClicked(QIconViewItem*)) ); + connect(this, SIGNAL(doubleClicked(QIconViewItem*)), + this, SLOT(slotDoubleClicked(QIconViewItem*)) ); + + connect(this, SIGNAL(dropped(QDropEvent*,const QValueList&)), + this, SLOT(slotDropped(QDropEvent*)) ); + connect(this, SIGNAL( contentsMoving( int, int )), + this, SLOT( slotContentsMoving( int, int ))); + connect(this, SIGNAL(currentChanged(QIconViewItem*)), + this, SLOT(slotCurrentChanged(QIconViewItem*)) ); + + QIconView::setSelectionMode(Extended); + + connect(BusyLevelManager::instance(), SIGNAL(busyLevelChanged(BusyLevel)), + this, SLOT( slotBusyLevelChanged(BusyLevel))); + + connect(d->mThumbnailUpdateTimer, SIGNAL(timeout()), + this, SLOT( startThumbnailUpdate()) ); +} + + +FileThumbnailView::~FileThumbnailView() { + stopThumbnailUpdate(); + FileViewConfig::setThumbnailDetails(d->mItemDetails); + FileViewConfig::setThumbnailTextPos( int(itemTextPos()) ); + FileViewConfig::writeConfig(); + delete d; +} + + +void FileThumbnailView::setThumbnailSize(int value) { + if (value==d->mThumbnailSize) return; + d->mThumbnailSize=value; + updateGrid(); + + KFileItemListIterator it( *items() ); + for ( ; it.current(); ++it ) { + KFileItem *item=it.current(); + QPixmap pixmap=createItemPixmap(item); + QIconViewItem* iconItem=viewItem(this, item); + if (iconItem) iconItem->setPixmap(pixmap); + } + arrangeItemsInGrid(); + d->mThumbnailUpdateTimer->start(THUMBNAIL_UPDATE_DELAY, true); +} + + +int FileThumbnailView::thumbnailSize() const { + return d->mThumbnailSize; +} + + +/** + * Overriden to call updateGrid + */ +void FileThumbnailView::setItemTextPos(ItemTextPos pos) { + QIconView::setItemTextPos(pos); + updateGrid(); +} + + +void FileThumbnailView::setMarginSize(int value) { + if (value==d->mMarginSize) return; + d->mMarginSize=value; + updateGrid(); +} + + +int FileThumbnailView::marginSize() const { + return d->mMarginSize; +} + + +void FileThumbnailView::setItemDetails(int details) { + d->mItemDetails=details; + for (QIconViewItem* item=firstItem(); item; item=item->nextItem()) { + static_cast(item)->updateLines(); + } + arrangeItemsInGrid(); +} + + +int FileThumbnailView::itemDetails() const { + return d->mItemDetails; +} + + +void FileThumbnailView::setThumbnailPixmap(const KFileItem* fileItem, const QPixmap& thumbnail, const QSize& size) { + FileThumbnailViewItem* iconItem=viewItem(this, fileItem); + if (!iconItem) return; + + iconItem->setPixmap(thumbnail); + + // Update item info + if (size.isValid()) { + iconItem->setImageSize(size); + } + iconItem->repaint(); + + // Notify progress + if (d->mProgressWidget) { + // mProgressWidget might be null if we get called after the thumbnail + // job finished. This can happen when the thumbnail job use KPreviewJob + // to generate a thumbnail. + d->mProgressWidget->progressBar()->advance(1); + } +} + + + + +void FileThumbnailView::setShownFileItem(KFileItem* fileItem) { + if( fileItem == mShownFileItem ) return; + FileThumbnailViewItem* oldShownItem=viewItem(this, mShownFileItem); + FileThumbnailViewItem* newShownItem=viewItem(this, fileItem); + + FileViewBase::setShownFileItem(fileItem); + if (oldShownItem) repaintItem(oldShownItem); + if (newShownItem) repaintItem(newShownItem); +} + + +//----------------------------------------------------------------------------- +// +// Thumbnail code +// +//----------------------------------------------------------------------------- +QPixmap FileThumbnailView::createItemPixmap(const KFileItem* item) const { + bool isDirOrArchive=item->isDir() || Archive::fileItemIsArchive(item); + if (!isDirOrArchive) { + if (d->mWaitThumbnail.width()!=d->mThumbnailSize) { + d->updateWaitThumbnail(this); + } + return d->mWaitThumbnail; + } + + QPixmap thumbnail(d->mThumbnailSize, d->mThumbnailSize); + thumbnail.fill(paletteBackgroundColor()); + QPainter painter(&thumbnail); + + // Load the icon + QPixmap itemPix=item->pixmap(QMIN(d->mThumbnailSize, ThumbnailSize::NORMAL)); + painter.drawPixmap( + (d->mThumbnailSize-itemPix.width())/2, + (d->mThumbnailSize-itemPix.height())/2, + itemPix); + + return thumbnail; +} + + +void FileThumbnailView::startThumbnailUpdate() { + // Delay thumbnail update if the widget is not visible + if (!isVisible()) { + d->mUpdateThumbnailsOnNextShow=true; + return; + } + d->mUpdateThumbnailsOnNextShow=false; + stopThumbnailUpdate(); // just in case + doStartThumbnailUpdate(items()); +} + + +void FileThumbnailView::doStartThumbnailUpdate(const KFileItemList* list) { + QValueVector imageList; + imageList.reserve( list->count()); + QPtrListIterator it(*list); + for (;it.current(); ++it) { + KFileItem* item=it.current(); + if (!item->isDir() && !Archive::fileItemIsArchive(item)) { + imageList.append( item ); + } + } + if (imageList.empty()) return; + + BusyLevelManager::instance()->setBusyLevel( this, BUSY_THUMBNAILS ); + + Q_ASSERT(!d->mProgressWidget); + d->mProgressWidget=new ProgressWidget(this, imageList.count() ); + + connect(d->mProgressWidget->stopButton(), SIGNAL(clicked()), + this, SLOT(stopThumbnailUpdate()) ); + d->mProgressWidget->show(); + + d->mThumbnailLoadJob = new ThumbnailLoadJob(&imageList, d->mThumbnailSize); + + connect(d->mThumbnailLoadJob, SIGNAL(thumbnailLoaded(const KFileItem*, const QPixmap&, const QSize&)), + this, SLOT(setThumbnailPixmap(const KFileItem*,const QPixmap&, const QSize&)) ); + connect(d->mThumbnailLoadJob, SIGNAL(result(KIO::Job*)), + this, SLOT(slotUpdateEnded()) ); + + slotBusyLevelChanged( BusyLevelManager::instance()->busyLevel()); + // start updating at visible position + slotContentsMoving( contentsX(), contentsY()); + d->mThumbnailLoadJob->start(); +} + + +void FileThumbnailView::stopThumbnailUpdate() { + if (!d->mThumbnailLoadJob.isNull()) { + d->mThumbnailLoadJob->kill(false); + } +} + + +void FileThumbnailView::slotUpdateEnded() { + Q_ASSERT(d->mProgressWidget); + delete d->mProgressWidget; + d->mProgressWidget=0L; + + BusyLevelManager::instance()->setBusyLevel( this, BUSY_NONE ); +} + + +void FileThumbnailView::updateThumbnail(const KFileItem* fileItem) { + if (fileItem->isDir() || Archive::fileItemIsArchive(fileItem)) { + return; + } + + ThumbnailLoadJob::deleteImageThumbnail(fileItem->url()); + if (d->mThumbnailLoadJob.isNull()) { + KFileItemList list; + list.append(fileItem); + doStartThumbnailUpdate(&list); + } else { + d->mThumbnailLoadJob->appendItem(fileItem); + } +} + +// temporarily stop loading thumbnails when busy loading the selected image, +// otherwise thumbnail loading slows it down +void FileThumbnailView::slotBusyLevelChanged(BusyLevel level) { + if( !d->mThumbnailLoadJob.isNull()) { + if( level > BUSY_THUMBNAILS ) { + d->mThumbnailLoadJob->suspend(); + } else { + d->mThumbnailLoadJob->resume(); + } + } +} + +//----------------------------------------------------------------------------- +// +// KFileView methods +// +//----------------------------------------------------------------------------- +void FileThumbnailView::clearView() { + stopThumbnailUpdate(); + mShownFileItem=0L; + QIconView::clear(); +} + + +void FileThumbnailView::insertItem(KFileItem* item) { + if (!item) return; + bool isDirOrArchive=item->isDir() || Archive::fileItemIsArchive(item); + + QPixmap thumbnail=createItemPixmap(item); + FileThumbnailViewItem* iconItem=new FileThumbnailViewItem(this,item->text(),thumbnail,item); + iconItem->setDropEnabled(isDirOrArchive); + + setSortingKey(iconItem, item); + item->setExtraData(this,iconItem); +} + + +void FileThumbnailView::updateView(const KFileItem* fileItem) { + if (!fileItem) return; + + FileThumbnailViewItem* iconItem=viewItem(this, fileItem); + if (iconItem) { + iconItem->setText(fileItem->text()); + updateThumbnail(fileItem); + } + sort(); +} + + +void FileThumbnailView::ensureItemVisible(const KFileItem* fileItem) { + if (!fileItem) return; + + FileThumbnailViewItem* iconItem=viewItem(this, fileItem); + if (iconItem) QIconView::ensureItemVisible(iconItem); +} + + +void FileThumbnailView::setCurrentItem(const KFileItem* fileItem) { + if (!fileItem) return; + + FileThumbnailViewItem* iconItem=viewItem(this, fileItem); + if (iconItem) QIconView::setCurrentItem(iconItem); +} + + +void FileThumbnailView::setSelected(const KFileItem* fileItem,bool enable) { + if (!fileItem) return; + + FileThumbnailViewItem* iconItem=viewItem(this, fileItem); + if (iconItem) QIconView::setSelected(iconItem, enable, true /* do not unselect others */); +} + + +bool FileThumbnailView::isSelected(const KFileItem* fileItem) const { + if (!fileItem) return false; + + FileThumbnailViewItem* iconItem=viewItem(this, fileItem); + if (!iconItem) return false; + + return iconItem->isSelected(); +} + + +void FileThumbnailView::removeItem(const KFileItem* fileItem) { + if (!fileItem) return; + + // Remove it from the image preview job + if (!d->mThumbnailLoadJob.isNull()) + d->mThumbnailLoadJob->itemRemoved(fileItem); + + if (fileItem==mShownFileItem) mShownFileItem=0L; + + // Remove it from our view + FileThumbnailViewItem* iconItem=viewItem(this, fileItem); + if (iconItem) delete iconItem; + KFileView::removeItem(fileItem); + arrangeItemsInGrid(); +} + + +KFileItem* FileThumbnailView::firstFileItem() const { + FileThumbnailViewItem* iconItem=static_cast(firstItem()); + if (!iconItem) return 0L; + return iconItem->fileItem(); +} + + +KFileItem* FileThumbnailView::prevItem(const KFileItem* fileItem) const { + const FileThumbnailViewItem* iconItem=viewItem(this, fileItem); + if (!iconItem) return 0L; + + iconItem=static_cast(iconItem->prevItem()); + if (!iconItem) return 0L; + + return iconItem->fileItem(); +} + + +KFileItem* FileThumbnailView::currentFileItem() const { + const QIconViewItem* iconItem=currentItem(); + if (!iconItem) return 0L; + + return static_cast(iconItem)->fileItem(); +} + + +KFileItem* FileThumbnailView::nextItem(const KFileItem* fileItem) const { + const FileThumbnailViewItem* iconItem=viewItem(this, fileItem); + if (!iconItem) return 0L; + + iconItem=static_cast(iconItem->nextItem()); + if (!iconItem) return 0L; + + return iconItem->fileItem(); +} + + +void FileThumbnailView::setSorting(QDir::SortSpec spec) { + KFileView::setSorting(spec); + + KFileItem *item; + KFileItemListIterator it( *items() ); + + for ( ; (item = it.current() ); ++it ) { + QIconViewItem* iconItem=viewItem(this, item); + if (iconItem) setSortingKey(iconItem, item); + } + + KIconView::sort(! (spec & QDir::Reversed) ); +} + +//-------------------------------------------------------------------------- +// +// Drop support +// +//-------------------------------------------------------------------------- +void FileThumbnailView::contentsDragEnterEvent(QDragEnterEvent* event) { + return event->accept( KURLDrag::canDecode(event) ); +} + + +void FileThumbnailView::slotDropped(QDropEvent* event) { + emit dropped(event,0L); +} + + +void FileThumbnailView::showEvent(QShowEvent* event) { + KIconView::showEvent(event); + if (!d->mUpdateThumbnailsOnNextShow) return; + + d->mUpdateThumbnailsOnNextShow=false; + QTimer::singleShot(0, this, SLOT(startThumbnailUpdate())); +} + + +//-------------------------------------------------------------------------- +// +// Private +// +//-------------------------------------------------------------------------- +void FileThumbnailView::updateGrid() { + if (itemTextPos()==Right) { + setGridX( + d->mThumbnailSize + + FileThumbnailViewItem::PADDING*3 + + RIGHT_TEXT_WIDTH); + } else { + setGridX( + QMAX(d->mThumbnailSize, BOTTOM_MIN_TEXT_WIDTH) + + FileThumbnailViewItem::PADDING*2); + } + setSpacing(d->mMarginSize); +} + + +void FileThumbnailView::setSortingKey(QIconViewItem *iconItem, const KFileItem *item) +{ + // see also setSorting() + QDir::SortSpec spec = KFileView::sorting(); + bool isDirOrArchive=item->isDir() || Archive::fileItemIsArchive(item); + + QString key; + if ( spec & QDir::Time ) { + time_t time = TimeUtils::getTime(item); + key=sortingKey(time, isDirOrArchive, spec); + + } else if ( spec & QDir::Size ) { + key=sortingKey( item->size(), isDirOrArchive, spec ); + + } else { + // Name or Unsorted + key=sortingKey( item->text(), isDirOrArchive, spec ); + } + + iconItem->setKey(key); +} + + +//-------------------------------------------------------------------------- +// +// Private slots +// +//-------------------------------------------------------------------------- +void FileThumbnailView::slotDoubleClicked(QIconViewItem* iconItem) { + if (!iconItem) return; + if (KGlobalSettings::singleClick()) return; + FileThumbnailViewItem* thumbItem=static_cast(iconItem); + + KFileItem* fileItem=thumbItem->fileItem(); + + if (fileItem->isDir() || Archive::fileItemIsArchive(fileItem)) { + emit executed(iconItem); + } +} + + +void FileThumbnailView::slotClicked(QIconViewItem* iconItem) { + if (!iconItem) return; + if (!KGlobalSettings::singleClick()) return; + FileThumbnailViewItem* thumbItem=static_cast(iconItem); + + KFileItem* fileItem=thumbItem->fileItem(); + + if (fileItem->isDir() || Archive::fileItemIsArchive(fileItem)) { + emit executed(iconItem); + } +} + +void FileThumbnailView::slotContentsMoving( int x, int y ) { + updateVisibilityInfo( x, y ); // use x,y, the signal is emitted before moving +} + +void FileThumbnailView::slotCurrentChanged(QIconViewItem* item ) { + // trigger generating thumbnails from the current one + updateVisibilityInfo( contentsX(), contentsY()); + prefetchDone(); + // if the first image is selected, no matter how, preload the next one + for( QIconViewItem* pos = item; + pos != NULL; + pos = pos->nextItem()) { + FileThumbnailViewItem* cur = static_cast< FileThumbnailViewItem* >( pos ); + if( cur->fileItem()->isDir() || Archive::fileItemIsArchive(cur->fileItem())) continue; + if( pos == item && pos->nextItem() != NULL ) { + d->mPrefetch = ImageLoader::loader( + static_cast( cur->nextItem() )->fileItem()->url(), + this, BUSY_PRELOADING ); + connect( d->mPrefetch, SIGNAL( imageLoaded( bool )), SLOT( prefetchDone())); + } + } +} + +/** + * when generating thumbnails, make the current thumbnail + * to be the next one processed by the thumbnail job, if visible, + * otherwise use the first visible thumbnail + */ +void FileThumbnailView::updateVisibilityInfo( int x, int y ) { + if (d->mThumbnailLoadJob.isNull()) return; + + QRect rect( x, y, visibleWidth(), visibleHeight()); + FileThumbnailViewItem* first = static_cast< FileThumbnailViewItem* >( findFirstVisibleItem( rect )); + if (!first) { + d->mThumbnailLoadJob->setPriorityItems(NULL,NULL,NULL); + return; + } + + FileThumbnailViewItem* last = static_cast< FileThumbnailViewItem* >( findLastVisibleItem( rect )); + Q_ASSERT(last); // If we get a first item, then there must be a last + + if (currentItem() && currentItem()->intersects(rect)) { + KFileItem* fileItem = currentFileItem(); + d->mThumbnailLoadJob->setPriorityItems(fileItem, + first->fileItem(), last->fileItem()); + return; + } + + d->mThumbnailLoadJob->setPriorityItems( + first->fileItem(), + first->fileItem(), + last->fileItem()); +} + +void FileThumbnailView::keyPressEvent( QKeyEvent* e ) { +// When the user presses e.g. the Down key, try to preload the next image in that direction. + if( e->key() != Key_Left + && e->key() != Key_Right + && e->key() != Key_Up + && e->key() != Key_Down ) return KIconView::keyPressEvent( e ); + + QIconViewItem* current = currentItem(); + KIconView::keyPressEvent( e ); + QIconViewItem* next = NULL; + if( current != currentItem() && currentItem() != NULL ) { // it actually moved + switch( e->key()) { + case Key_Left: + next = currentItem()->prevItem(); + break; + case Key_Right: + next = currentItem()->nextItem(); + break; + case Key_Up: + // This relies on the thumbnails being in a grid ( x() == x() ) + for( next = currentItem()->prevItem(); + next != NULL && next->x() != currentItem()->x(); + next = next->prevItem()) + ; + break; + case Key_Down: + for( next = currentItem()->nextItem(); + next != NULL && next->x() != currentItem()->x(); + next = next->nextItem()) + ; + break; + } + + } + prefetchDone(); + if( next != NULL ) { + d->mPrefetch = ImageLoader::loader( + static_cast( next )->fileItem()->url(), + this, BUSY_PRELOADING ); + connect( d->mPrefetch, SIGNAL( imageLoaded( bool )), SLOT( prefetchDone())); + } +} + +void FileThumbnailView::prefetchDone() { + if( d->mPrefetch != NULL ) { + d->mPrefetch->release( this ); + d->mPrefetch = NULL; + } +} + +//-------------------------------------------------------------------------- +// +// Protected +// +//-------------------------------------------------------------------------- +void FileThumbnailView::startDrag() { + /** + * The item drawer for DragPixmapGenerator + */ + struct ItemDrawer : public DragPixmapItemDrawer { + ItemDrawer(FileThumbnailView* view) + : mView(view) {} + + QSize itemSize(KFileItem* fileItem) { + QPixmap* pix = pixmapFromFileItem(fileItem); + if (!pix) return QSize(); + + QSize size = pix->size(); + int maxWidth = mGenerator->maxWidth(); + if (size.width() > maxWidth) { + size.rheight() = size.height() * maxWidth / size.width(); + size.rwidth() = maxWidth; + } + return size; + } + + int spacing() const { + return 2; + } + + void drawItem(QPainter* painter, int left, int top, KFileItem* fileItem) { + QPixmap* pix = pixmapFromFileItem(fileItem); + if (!pix) return; + + QSize size = itemSize(fileItem); + left += (mGenerator->pixmapWidth() - size.width()) / 2; + if (size == pix->size()) { + painter->drawPixmap(left, top, *pix); + return; + } + + QImage img = pix->convertToImage(); + img = img.smoothScale(size, QImage::ScaleMin); + painter->drawImage(left, top, img); + } + + QPixmap* pixmapFromFileItem(KFileItem* fileItem) { + FileThumbnailViewItem* iconItem = viewItem(mView, fileItem); + Q_ASSERT(iconItem); + if (!iconItem) return 0; + + QPixmap* pix = iconItem->pixmap(); + Q_ASSERT(pix); + if (!pix) return 0; + return pix; + } + + FileThumbnailView* mView; + }; + ItemDrawer drawer(this); + + + KURL::List urls; + KFileItemListIterator it(*KFileView::selectedItems()); + + DragPixmapGenerator generator; + generator.setItemDrawer(&drawer); + + for ( ; it.current(); ++it ) { + urls.append(it.current()->url()); + generator.addItem(it.current()); + } + + if (urls.isEmpty()) { + kdWarning() << "No item to drag\n"; + return; + } + + QDragObject* drag=new KURLDrag(urls, this, 0); + QPixmap dragPixmap = generator.generate(); + + drag->setPixmap( dragPixmap, QPoint(generator.DRAG_OFFSET, -generator.DRAG_OFFSET)); + drag->dragCopy(); +} + + +void FileThumbnailView::showThumbnailDetailsDialog() { + if (!d->mThumbnailsDetailDialog) { + d->mThumbnailsDetailDialog = new ThumbnailDetailsDialog(this); + } + d->mThumbnailsDetailDialog->show(); +} + + +} // namespace diff --git a/src/gvcore/filethumbnailview.h b/src/gvcore/filethumbnailview.h new file mode 100644 index 0000000..25258b7 --- /dev/null +++ b/src/gvcore/filethumbnailview.h @@ -0,0 +1,131 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef FILETHUMBNAILVIEW_H +#define FILETHUMBNAILVIEW_H + +// Qt includes +#include +#include + +// KDE includes +#include + +// Our includes +#include "fileviewbase.h" +#include "busylevelmanager.h" +#include "libgwenview_export.h" + +class QDragEnterEvent; +class QIconViewItem; +class QPopupMenu; +class QShowEvent; + +class KConfig; +class KFileItem; +typedef QPtrList KFileItemList; + +namespace Gwenview { +class FileThumbnailViewItem; + +class LIBGWENVIEW_EXPORT FileThumbnailView : public KIconView, public FileViewBase { +Q_OBJECT + friend class FileThumbnailViewItem; + +public: + enum ItemDetail { FILENAME=1, FILESIZE=2, FILEDATE=4, IMAGESIZE=8 }; + FileThumbnailView(QWidget* parent); + ~FileThumbnailView(); + + QWidget* widget() { return this; } + + // KFileView methods + void clearView(); + void clearSelection() { QIconView::clearSelection(); } + void insertItem(KFileItem* item); + void ensureItemVisible(const KFileItem* item); + void setCurrentItem(const KFileItem* item); + void setSelected(const KFileItem* item,bool enable); + bool isSelected(const KFileItem* item) const; + void removeItem(const KFileItem* item); + void updateView(const KFileItem* item); + void setSorting(QDir::SortSpec); + + KFileItem* firstFileItem() const; + KFileItem* prevItem( const KFileItem*) const; + KFileItem* currentFileItem() const; + KFileItem* nextItem( const KFileItem*) const; + + void setThumbnailSize(int value); + int thumbnailSize() const; + + void setMarginSize(int value); + int marginSize() const; + + void setItemDetails(int); + int itemDetails() const; + + void setItemTextPos(ItemTextPos); + + void setShownFileItem(KFileItem*); + + void updateThumbnail(const KFileItem*); + +public slots: + void setThumbnailPixmap(const KFileItem*,const QPixmap&, const QSize&); + void startThumbnailUpdate(); + void stopThumbnailUpdate(); + + void showThumbnailDetailsDialog(); + +signals: + void dropped(QDropEvent*, KFileItem* target); + +protected: + void showEvent(QShowEvent*); + void contentsDragEnterEvent(QDragEnterEvent*); + void startDrag(); + virtual void keyPressEvent( QKeyEvent* ); + +private: + class Private; + Private* d; + + void updateGrid(); + QPixmap createItemPixmap(const KFileItem*) const; + void doStartThumbnailUpdate(const KFileItemList*); + void setSortingKey(QIconViewItem*, const KFileItem*); + void updateVisibilityInfo( int x, int y ); + +private slots: + void slotClicked(QIconViewItem*); + void slotDoubleClicked(QIconViewItem*); + void slotDropped(QDropEvent*); + void slotContentsMoving( int, int ); + void slotCurrentChanged(QIconViewItem*); + void slotBusyLevelChanged( BusyLevel ); + void slotUpdateEnded(); + void prefetchDone(); +}; + + +} // namespace +#endif + diff --git a/src/gvcore/filethumbnailviewitem.cpp b/src/gvcore/filethumbnailviewitem.cpp new file mode 100644 index 0000000..df4e548 --- /dev/null +++ b/src/gvcore/filethumbnailviewitem.cpp @@ -0,0 +1,394 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* Gwenview - A simple image viewer for KDE + Copyright 2000-2004 Aurlien Gteau + This class is based on the KIconViewItem class from KDE libs. + Original copyright follows. +*/ +/* This file is part of the KDE libraries + Copyright (C) 1999 Torben Weis + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +// Qt includes +#include +#include +#include +#include +#include + +// KDE includes +#include +#include +#include + +// Our includes +#include "archive.h" +#include "filethumbnailview.h" +#include "filethumbnailviewitem.h" +#include "fileviewconfig.h" +#include "timeutils.h" + +namespace Gwenview { + +const int SHOWN_ITEM_INDICATOR_SIZE = 8; + +#if 0 +static void printRect(const QString& txt,const QRect& rect) { + kdWarning() << txt << " : " << rect.x() << "x" << rect.y() << " " << rect.width() << "x" << rect.height() << endl; +} +#endif + + +/** + * An helper class to handle a caption line and help drawing it + */ +class FileThumbnailViewItem::Line { +protected: + const QIconViewItem* mItem; + QString mTxt; + int mWidth; +public: + Line(const QIconViewItem* item, const QString& txt) + : mItem(item) + , mTxt(txt) + , mWidth(-1) { + } + virtual ~Line() {} + + virtual void setWidth(int width) { + mWidth=width; + } + + virtual int height() const=0; + + void paint(QPainter* p, int textX, int textY, int align) const { + Q_ASSERT(mWidth!=-1); + int length=fontMetrics().width(mTxt); + if (length<=mWidth ) { + p->drawText( + textX, + textY, + mWidth, + fontMetrics().height(), + align, + mTxt); + } else { + p->save(); + complexPaint(p, textX, textY, align); + p->restore(); + } + }; + +protected: + const FileThumbnailView* view() const { + return static_cast(mItem->iconView()); + } + + QFontMetrics fontMetrics() const { + return view()->fontMetrics(); + } + + /** + * Called when the text won't fit the available space + */ + virtual void complexPaint(QPainter* p, int textX, int textY, int align) const=0; +}; + + +/** + * A line which will get cropped if necessary + */ +class FileThumbnailViewItem::CroppedLine : public FileThumbnailViewItem::Line { +public: + CroppedLine(const QIconViewItem* item, const QString& txt) + : Line(item, txt) {} + + int height() const { + return fontMetrics().height(); + } + + void complexPaint(QPainter* p, int textX, int textY, int /*align*/) const { + KWordWrap::drawFadeoutText(p, + textX, + textY + fontMetrics().ascent(), + mWidth, + mTxt); + } +}; + +/** + * A line which will get wrapped if necessary + */ + +class FileThumbnailViewItem::WrappedLine : public FileThumbnailViewItem::Line { + KWordWrap* mWordWrap; +public: + WrappedLine(const QIconViewItem* item, const QString& txt) + : Line(item, txt) + , mWordWrap(0) {} + + ~WrappedLine() { + delete mWordWrap; + } + + int height() const { + Q_ASSERT(mWordWrap); + if (!mWordWrap) return 0; + return mWordWrap->boundingRect().height(); + } + + /** + * Regenerates mWordWrap if the width has changed + */ + void setWidth(int width) { + if (width==mWidth) return; + mWidth=width; + delete mWordWrap; + QFontMetrics fm=fontMetrics(); + mWordWrap=KWordWrap::formatText(fm, + QRect(0, 0, mWidth, fm.height()*3), + 0 /*flags*/, + mTxt); + } + + void complexPaint(QPainter* p, int textX, int textY, int align) const { + Q_ASSERT(mWordWrap); + if (!mWordWrap) return; + + int xpos=0; + if (align & AlignHCenter) { + xpos=( mWidth - mWordWrap->boundingRect().width() ) / 2; + } + + mWordWrap->drawText(p, + textX + xpos, + textY, + align); + } +}; + + +FileThumbnailViewItem::FileThumbnailViewItem(QIconView* view,const QString& text,const QPixmap& icon, KFileItem* fileItem) +: QIconViewItem(view,text,icon), mFileItem(fileItem) { + updateLines(); + calcRect(); +} + + +FileThumbnailViewItem::~FileThumbnailViewItem() { + QValueVector::ConstIterator it=mLines.begin(); + QValueVector::ConstIterator itEnd=mLines.end(); + for (;it!=itEnd; ++it) { + delete *it; + } +} + + +void FileThumbnailViewItem::updateLines() { + QValueVector::ConstIterator it=mLines.begin(); + QValueVector::ConstIterator itEnd=mLines.end(); + for (;it!=itEnd; ++it) { + delete *it; + } + mLines.clear(); + if (!mFileItem) return; + + bool isDir=mFileItem->isDir(); + if (iconView()->itemTextPos()==QIconView::Right) { + // Text is on the right, show everything + + time_t time = TimeUtils::getTime(mFileItem); + mLines.append( new WrappedLine(this, mFileItem->name()) ); + mLines.append( new CroppedLine(this, TimeUtils::formatTime(time)) ); + if (mImageSize.isValid()) { + QString txt=QString::number(mImageSize.width())+"x"+QString::number(mImageSize.height()); + mLines.append( new CroppedLine(this, txt) ); + } + if (!isDir) { + mLines.append( new CroppedLine(this, KIO::convertSize(mFileItem->size())) ); + } + + } else { + // Text is below the icon, only show details selected in + // view->itemDetails() + FileThumbnailView *view=static_cast(iconView()); + int details=view->itemDetails(); + bool isImage=!Archive::fileItemIsDirOrArchive(mFileItem); + + if (!isImage || (details & FileThumbnailView::FILENAME)) { + mLines.append( new WrappedLine(this, mFileItem->name()) ); + } + if (details & FileThumbnailView::FILEDATE) { + time_t time = TimeUtils::getTime(mFileItem); + mLines.append( new CroppedLine(this, TimeUtils::formatTime(time)) ); + } + if (details & FileThumbnailView::IMAGESIZE) { + QString txt; + if (mImageSize.isValid()) { + txt=QString::number(mImageSize.width())+"x"+QString::number(mImageSize.height()); + } + mLines.append( new CroppedLine(this, txt) ); + } + if (!isDir && (details & FileThumbnailView::FILESIZE)) { + mLines.append( new CroppedLine(this, KIO::convertSize(mFileItem->size())) ); + } + + } + + calcRect(); +} + + +void FileThumbnailViewItem::calcRect(const QString&) { + FileThumbnailView *view=static_cast(iconView()); + bool isRight=view->itemTextPos()==QIconView::Right; + + int textW=view->gridX(); + int thumbnailSize=FileViewConfig::thumbnailSize(); + if (isRight) { + textW-=PADDING * 3 + thumbnailSize; + } else { + textW-=PADDING * 2; + } + + int textH=0; + QValueVector::ConstIterator it=mLines.begin(); + QValueVector::ConstIterator itEnd=mLines.end(); + for (;it!=itEnd; ++it) { + (*it)->setWidth(textW); + textH+=(*it)->height(); + } + + QRect itemRect(x(), y(), view->gridX(), 0); + QRect itemPixmapRect(PADDING, PADDING, thumbnailSize, thumbnailSize); + QRect itemTextRect(0, 0, textW, textH); + if (isRight) { + itemRect.setHeight( QMAX(thumbnailSize + PADDING*2, textH) ); + itemTextRect.moveLeft(thumbnailSize + PADDING * 2 ); + itemTextRect.moveTop((itemRect.height() - textH)/2); + } else { + itemPixmapRect.moveLeft( (itemRect.width() - itemPixmapRect.width()) / 2 ); + itemRect.setHeight(thumbnailSize + PADDING*3 + textH); + itemTextRect.moveLeft(PADDING); + itemTextRect.moveTop(thumbnailSize + PADDING * 2); + } + + // Update rects + if ( itemPixmapRect != pixmapRect() ) { + setPixmapRect( itemPixmapRect ); + } + if ( itemTextRect != textRect() ) { + setTextRect( itemTextRect ); + } + if ( itemRect != rect() ) { + setItemRect( itemRect ); + } +} + + +void FileThumbnailViewItem::paintItem(QPainter *p, const QColorGroup &cg) { + FileThumbnailView *view=static_cast(iconView()); + Q_ASSERT(view); + if (!view) return; + + bool isRight=view->itemTextPos()==QIconView::Right; + bool isShownItem=view->shownFileItem() && view->shownFileItem()->extraData(view)==this; + bool isImage=!Archive::fileItemIsDirOrArchive(mFileItem); + int textX, textY, textW, textH; + int thumbnailSize=FileViewConfig::thumbnailSize(); + + textX=textRect(false).x(); + textY=textRect(false).y(); + textW=textRect(false).width(); + textH=textRect(false).height(); + + // Draw pixmap + QRect pRect = pixmapRect(false); + int pixX = pRect.left() + ( thumbnailSize - pixmap()->width() ) / 2; + int pixY = pRect.top() + ( thumbnailSize - pixmap()->height() ) / 2; + p->drawPixmap( pixX, pixY, *pixmap() ); + + QColor bg; + if ( isSelected() ) { + bg=cg.highlight(); + } else { + bg=cg.mid(); + } + + // Draw shown item indicator + if (isShownItem) { + QPointArray pa(3); + pa[0] = pixmapRect(false).bottomLeft(); + pa[0].rx() += pixmapRect(false).width() / 2; + pa[0].ry() += PADDING - 1; + pa[0].ry() -= SHOWN_ITEM_INDICATOR_SIZE; + + pa[1] = pa[0]; + pa[1].rx() -= SHOWN_ITEM_INDICATOR_SIZE; + pa[1].ry() += SHOWN_ITEM_INDICATOR_SIZE; + + pa[2] = pa[1]; + pa[2].rx() += SHOWN_ITEM_INDICATOR_SIZE * 2; + + p->setBrush(cg.highlight()); + p->setPen(cg.base()); + p->drawPolygon(pa); + } + + if (isImage || isSelected()) { + // Draw frame + QRect frmRect=pixmapRect(false); + frmRect.addCoords(-PADDING, -PADDING, PADDING, PADDING); + + p->setBrush(QBrush()); + p->setPen(bg); + p->drawRect(frmRect); + if (isSelected()) { + frmRect.addCoords(1, 1, -1, -1); + p->drawRect(frmRect); + } + } + + // Draw text + p->setPen(cg.text()); + p->setBackgroundColor(cg.base()); + int align = (isRight ? AlignAuto : AlignHCenter) | AlignTop; + + QValueVector::ConstIterator it=mLines.begin(); + QValueVector::ConstIterator itEnd=mLines.end(); + for (;it!=itEnd; ++it) { + const Line* line=*it; + line->paint(p, textX, textY, align); + textY+=line->height(); + } +} + + +bool FileThumbnailViewItem::acceptDrop(const QMimeSource* source) const { + return KURLDrag::canDecode(source); +} + + +void FileThumbnailViewItem::dropped(QDropEvent* event, const QValueList&) { + FileThumbnailView *view=static_cast(iconView()); + emit view->dropped(event,mFileItem); +} + +void FileThumbnailViewItem::setImageSize(const QSize& size) { + mImageSize=size; + updateLines(); +} + +} // namespace diff --git a/src/gvcore/filethumbnailviewitem.h b/src/gvcore/filethumbnailviewitem.h new file mode 100644 index 0000000..154c4b7 --- /dev/null +++ b/src/gvcore/filethumbnailviewitem.h @@ -0,0 +1,69 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef FILETHUMBNAILVIEWITEM_H +#define FILETHUMBNAILVIEWITEM_H + +// Qt +#include +#include +#include +#include + +class KFileItem; + +namespace Gwenview { +/** + * We override the QIconViewItem to control the look of selected items + * and get a pointer to our KFileItem + */ +class FileThumbnailViewItem : public QIconViewItem { +public: + class Line; + class CroppedLine; + class WrappedLine; + enum { PADDING=4 }; + + FileThumbnailViewItem(QIconView* parent,const QString& text,const QPixmap& icon, KFileItem* fileItem); + ~FileThumbnailViewItem(); + + KFileItem* fileItem() const { return mFileItem; } + + void setImageSize(const QSize&); + + void updateLines(); + +protected: + void paintItem(QPainter* painter, const QColorGroup& colorGroup); + void calcRect( const QString& text_=QString::null ); + void paintFocus(QPainter*, const QColorGroup&) {} + bool acceptDrop(const QMimeSource*) const; + void dropped(QDropEvent*, const QValueList&); + + KFileItem* mFileItem; + QValueVector mLines; + + QSize mImageSize; +}; + +} // namespace +#endif + diff --git a/src/gvcore/fileviewbase.h b/src/gvcore/fileviewbase.h new file mode 100644 index 0000000..9d36598 --- /dev/null +++ b/src/gvcore/fileviewbase.h @@ -0,0 +1,47 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef FILEVIEWBASE_H +#define FILEVIEWBASE_H + +// Qt includes +#include + +// KDE includes +#include +namespace Gwenview { + +class FileViewBase : public KFileView { +public: + FileViewBase() : mShownFileItem(0L) {} + + KFileItem* shownFileItem() const { return mShownFileItem; } + virtual void setShownFileItem(KFileItem* fileItem) { mShownFileItem=fileItem; } + + virtual void updateFromSettings() {} + +protected: + KFileItem* mShownFileItem; +}; + +} // namespace +#endif + diff --git a/src/gvcore/fileviewconfig.kcfg b/src/gvcore/fileviewconfig.kcfg new file mode 100644 index 0000000..0ef5f1a --- /dev/null +++ b/src/gvcore/fileviewconfig.kcfg @@ -0,0 +1,62 @@ + + + + qiconview.h + + + + true + + + false + + + true + + + QIconView::Right + + + 48 + + + 5 + + + 9 + + This is a bit set of FileThumbnailView::ItemDetail: + enum ItemDetail { FILENAME=1, FILESIZE=2, FILEDATE=4, IMAGESIZE=8 }; + + + + All + + + + + + + + false + + + + + + + + + + + true + + + + + false + + + + + diff --git a/src/gvcore/fileviewconfig.kcfgc b/src/gvcore/fileviewconfig.kcfgc new file mode 100644 index 0000000..ae7a375 --- /dev/null +++ b/src/gvcore/fileviewconfig.kcfgc @@ -0,0 +1,7 @@ +File=fileviewconfig.kcfg +ClassName=FileViewConfig +NameSpace=Gwenview +Singleton=true +Mutators=true +IncludeFiles=gvcore/libgwenview_export.h +Visibility=LIBGWENVIEW_EXPORT diff --git a/src/gvcore/fileviewcontroller.cpp b/src/gvcore/fileviewcontroller.cpp new file mode 100644 index 0000000..5daf10b --- /dev/null +++ b/src/gvcore/fileviewcontroller.cpp @@ -0,0 +1,1321 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// Qt +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "archive.h" +#include "cache.h" +#include "clicklineedit.h" +#include "cursortracker.h" +#include "filedetailview.h" +#include "fileoperation.h" +#include "filethumbnailview.h" +#include "filterbar.h" +#include "imageloader.h" +#include "mimetypeutils.h" +#include "timeutils.h" +#include "thumbnailsize.h" +#include "fileviewconfig.h" +#include "miscconfig.h" + +#include "fileviewcontroller.moc" +namespace Gwenview { + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +static const int SLIDER_RESOLUTION=4; + + +//----------------------------------------------------------------------- +// +// internal class which allows dynamically turning off visual error reporting +// +//----------------------------------------------------------------------- +class DirLister : public KDirLister { +public: + DirLister() + : KDirLister() + , mError(false) + , mCheck(false) {} + + virtual bool validURL(const KURL& url) const { + if( !url.isValid()) mError = true; + if( mCheck ) return KDirLister::validURL( url ); + return url.isValid(); + } + + virtual void handleError(KIO::Job* job) { + mError = true; + if(mCheck) KDirLister::handleError( job ); + }; + + bool error() const { + return mError; + } + + void clearError() { + mError = false; + } + + void setCheck(bool c) { + mCheck = c; + } + + void setDateFilter(const QDate& from, const QDate& to) { + mFromDate = from; + mToDate =to; + } + + virtual bool itemMatchFilters(const KFileItem* item) const { + if (!matchesFilter(item)) return false; + return matchesMimeFilter(item); + } + +public: + virtual bool matchesMimeFilter(const KFileItem* item) const { + // Do mime filtering ourself because we use startsWith instead of == + QStringList lst = mimeFilters(); + QStringList::Iterator it = lst.begin(), end = lst.end(); + bool result = false; + QString type = item->mimetype(); + for (; it!=end; ++it) { + if (type.startsWith(*it)) { + result = true; + break; + } + } + if (!result) return false; + + if (item->isDir() || Archive::fileItemIsArchive(item)) { + // Do not filter out dirs or archives + return true; + } + + if (!mFromDate.isValid() && !mToDate.isValid()) return result; + + // Convert item time to a QDate + time_t time=TimeUtils::getTime(item); + QDateTime dateTime; + dateTime.setTime_t(time); + QDate date=dateTime.date(); + + if (mFromDate.isValid() && date < mFromDate) return false; + if (mToDate.isValid() && date > mToDate) return false; + return true; + } + +private: + mutable bool mError; + bool mCheck; + QDate mFromDate; + QDate mToDate; +}; + + +//----------------------------------------------------------------------- +// +// FileViewController::Private +// +//----------------------------------------------------------------------- +class FileViewController::Private { +public: + ~Private() { + delete mSliderTracker; + } + FileViewController* that; + FilterBar* mFilterBar; + KToolBar* mToolBar; + QWidgetStack* mStack; + KSelectAction* mSortAction; + KToggleAction* mRevertSortAction; + TipTracker* mSliderTracker; + + QHBox* mFilterHBox; + QComboBox* mFilterComboBox; + QCheckBox* mShowFilterBarCheckBox; + + void initFilterBar() { + mFilterBar=new FilterBar(that); + mFilterBar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + mFilterBar->hide(); + + QIconSet resetIS=BarIcon("locationbar_erase"); + mFilterBar->mResetNameCombo->setIconSet(resetIS); + mFilterBar->mResetFrom->setIconSet(resetIS); + mFilterBar->mResetTo->setIconSet(resetIS); + + QObject::connect( + mFilterBar->mResetNameCombo, SIGNAL(clicked()), + that, SLOT(resetNameFilter()) ); + QObject::connect( + mFilterBar->mResetFrom, SIGNAL(clicked()), + that, SLOT(resetFromFilter()) ); + QObject::connect( + mFilterBar->mResetTo, SIGNAL(clicked()), + that, SLOT(resetToFilter()) ); + + QObject::connect( + mFilterBar->mFilterButton, SIGNAL(clicked()), + that, SLOT(applyFilter()) ); + } + + void initFilterCombo() { + mFilterHBox=new QHBox(mToolBar, "kde toolbar widget"); + mFilterHBox->setSpacing(KDialog::spacingHint()); + + mFilterComboBox=new QComboBox(mFilterHBox); + mFilterComboBox->insertItem(i18n("All files"), ALL); + mFilterComboBox->insertItem(i18n("Images only"), IMAGES_ONLY); + mFilterComboBox->insertItem(i18n("Videos only"), VIDEOS_ONLY); + + QObject::connect( + mFilterComboBox, SIGNAL(activated(int)), + that, SLOT(applyFilter()) ); + + mShowFilterBarCheckBox = new QCheckBox(i18n("More"), mFilterHBox); + QObject::connect( + mShowFilterBarCheckBox, SIGNAL(toggled(bool)), + mFilterBar, SLOT(setShown(bool)) ); + QObject::connect( + mShowFilterBarCheckBox, SIGNAL(toggled(bool)), + that, SLOT(applyFilter()) ); + } + + + void loadFilterSettings() { + mFilterComboBox->setCurrentItem(FileViewConfig::filterMode()); + mShowFilterBarCheckBox->setChecked(FileViewConfig::showFilterBar()); + mFilterBar->mNameEdit->setText(FileViewConfig::nameFilter()); + mFilterBar->mFromDateEdit->setDate(FileViewConfig::fromDateFilter().date()); + mFilterBar->mToDateEdit->setDate(FileViewConfig::toDateFilter().date()); + } +}; + + +//----------------------------------------------------------------------- +// +// FileViewController +// +//----------------------------------------------------------------------- +FileViewController::FileViewController(QWidget* parent,KActionCollection* actionCollection) +: QWidget(parent) +, mMode(FILE_LIST) +, mPrefetch( NULL ) +, mChangeDirStatus(CHANGE_DIR_STATUS_NONE) +, mBrowsing(false) +, mSelecting(false) +{ + d=new Private; + d->that=this; + setMinimumWidth(1); + d->mToolBar=new KToolBar(this, "", true); + d->initFilterBar(); + d->initFilterCombo(); + d->mStack=new QWidgetStack(this); + + QVBoxLayout *layout=new QVBoxLayout(this); + layout->addWidget(d->mToolBar); + layout->addWidget(d->mFilterBar); + layout->addWidget(d->mStack); + + // Actions + mSelectFirst=new KAction(i18n("&First"), + QApplication::reverseLayout() ? "2rightarrow":"2leftarrow", Key_Home, + this,SLOT(slotSelectFirst()), actionCollection, "first"); + + mSelectLast=new KAction(i18n("&Last"), + QApplication::reverseLayout() ? "2leftarrow":"2rightarrow", Key_End, + this,SLOT(slotSelectLast()), actionCollection, "last"); + + mSelectPrevious=new KAction(i18n("&Previous"), + QApplication::reverseLayout() ? "1rightarrow":"1leftarrow", Key_BackSpace, + this,SLOT(slotSelectPrevious()), actionCollection, "previous"); + + mSelectNext=new KAction(i18n("&Next"), + QApplication::reverseLayout() ? "1leftarrow":"1rightarrow", Key_Space, + this,SLOT(slotSelectNext()), actionCollection, "next"); + + mSelectPreviousDir=new KAction(i18n("&Previous Folder"), + QApplication::reverseLayout() ? "player_fwd":"player_rew", ALT + Key_BackSpace, + this,SLOT(slotSelectPreviousDir()), actionCollection, "previous_folder"); + + mSelectNextDir=new KAction(i18n("&Next Folder"), + QApplication::reverseLayout() ? "player_rew":"player_fwd", ALT + Key_Space, + this,SLOT(slotSelectNextDir()), actionCollection, "next_folder"); + + mSelectFirstSubDir=new KAction(i18n("&First Sub Folder"), "down", ALT + Key_Down, + this,SLOT(slotSelectFirstSubDir()), actionCollection, "first_sub_folder"); + + mListMode=new KRadioAction(i18n("Details"),"view_detailed",0,this,SLOT(updateViewMode()),actionCollection,"list_mode"); + mListMode->setExclusiveGroup("thumbnails"); + mSideThumbnailMode=new KRadioAction(i18n("Thumbnails with Info on Side"),"view_multicolumn",0,this,SLOT(updateViewMode()),actionCollection,"side_thumbnail_mode"); + mSideThumbnailMode->setExclusiveGroup("thumbnails"); + mBottomThumbnailMode=new KRadioAction(i18n("Thumbnails with Info on Bottom"),"view_icon",0,this,SLOT(updateViewMode()),actionCollection,"bottom_thumbnail_mode"); + mBottomThumbnailMode->setExclusiveGroup("thumbnails"); + + // Size slider + mSizeSlider=new QSlider(Horizontal, d->mToolBar); + mSizeSlider->setFixedWidth(120); + mSizeSlider->setRange( + ThumbnailSize::MIN/SLIDER_RESOLUTION, + ThumbnailSize::LARGE/SLIDER_RESOLUTION); + mSizeSlider->setValue(FileViewConfig::thumbnailSize() / SLIDER_RESOLUTION); + + connect(mSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(updateThumbnailSize(int)) ); + connect(mListMode, SIGNAL(toggled(bool)), mSizeSlider, SLOT(setDisabled(bool)) ); + KAction* sliderAction=new KWidgetAction(mSizeSlider, i18n("Thumbnail Size"), 0, 0, 0, actionCollection, "size_slider"); + d->mSliderTracker=new TipTracker("", mSizeSlider); + // /Size slider + + mShowDotFiles=new KToggleAction(i18n("Show &Hidden Files"),CTRL + Key_H,this,SLOT(toggleShowDotFiles()),actionCollection,"show_dot_files"); + + d->mSortAction=new KSelectAction(i18n("Sort"), 0, this, SLOT(setSorting()), actionCollection, "view_sort"); + QStringList sortItems; + sortItems << i18n("By Name") << i18n("By Date") << i18n("By Size"); + d->mSortAction->setItems(sortItems); + d->mSortAction->setCurrentItem(0); + + d->mRevertSortAction=new KToggleAction(i18n("Descending"),0, this, SLOT(setSorting()), actionCollection, "descending"); + QPopupMenu* sortMenu=d->mSortAction->popupMenu(); + Q_ASSERT(sortMenu); + sortMenu->insertSeparator(); + d->mRevertSortAction->plug(sortMenu); + + // Dir lister + mDirLister=new DirLister; + mDirLister->setMainWindow(topLevelWidget()); + connect(mDirLister,SIGNAL(clear()), + this,SLOT(dirListerClear()) ); + + connect(mDirLister,SIGNAL(newItems(const KFileItemList&)), + this,SLOT(dirListerNewItems(const KFileItemList&)) ); + + connect(mDirLister,SIGNAL(deleteItem(KFileItem*)), + this,SLOT(dirListerDeleteItem(KFileItem*)) ); + + connect(mDirLister,SIGNAL(refreshItems(const KFileItemList&)), + this,SLOT(dirListerRefreshItems(const KFileItemList&)) ); + + connect(mDirLister,SIGNAL(started(const KURL&)), + this,SLOT(dirListerStarted()) ); + + connect(mDirLister,SIGNAL(completed()), + this,SLOT(dirListerCompleted()) ); + + connect(mDirLister,SIGNAL(canceled()), + this,SLOT(dirListerCanceled()) ); + + // Propagate canceled signals + connect(mDirLister,SIGNAL(canceled()), + this,SIGNAL(canceled()) ); + + // File detail widget + mFileDetailView=new FileDetailView(d->mStack, "filedetailview"); + d->mStack->addWidget(mFileDetailView,0); + mFileDetailView->viewport()->installEventFilter(this); + + connect(mFileDetailView,SIGNAL(executed(QListViewItem*)), + this,SLOT(slotViewExecuted()) ); + connect(mFileDetailView,SIGNAL(returnPressed(QListViewItem*)), + this,SLOT(slotViewExecuted()) ); + connect(mFileDetailView,SIGNAL(currentChanged(QListViewItem*)), + this,SLOT(slotViewClicked()) ); + connect(mFileDetailView,SIGNAL(selectionChanged()), + this,SLOT(slotViewClicked()) ); + connect(mFileDetailView,SIGNAL(clicked(QListViewItem*)), + this,SLOT(slotViewClicked()) ); + connect(mFileDetailView,SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this,SLOT(openContextMenu(KListView*, QListViewItem*, const QPoint&)) ); + connect(mFileDetailView,SIGNAL(dropped(QDropEvent*,KFileItem*)), + this,SLOT(openDropURLMenu(QDropEvent*, KFileItem*)) ); + connect(mFileDetailView, SIGNAL(sortingChanged(QDir::SortSpec)), + this, SLOT(updateSortMenu(QDir::SortSpec)) ); + connect(mFileDetailView, SIGNAL(doubleClicked(QListViewItem*)), + this, SLOT(slotViewDoubleClicked()) ); + connect(mFileDetailView, SIGNAL(selectionChanged()), + this, SIGNAL(selectionChanged()) ); + + // Thumbnail widget + mFileThumbnailView=new FileThumbnailView(d->mStack); + d->mStack->addWidget(mFileThumbnailView,1); + mFileThumbnailView->viewport()->installEventFilter(this); + + connect(mFileThumbnailView,SIGNAL(executed(QIconViewItem*)), + this,SLOT(slotViewExecuted()) ); + connect(mFileThumbnailView,SIGNAL(returnPressed(QIconViewItem*)), + this,SLOT(slotViewExecuted()) ); + connect(mFileThumbnailView,SIGNAL(currentChanged(QIconViewItem*)), + this,SLOT(slotViewClicked()) ); + connect(mFileThumbnailView,SIGNAL(selectionChanged()), + this,SLOT(slotViewClicked()) ); + connect(mFileThumbnailView,SIGNAL(clicked(QIconViewItem*)), + this,SLOT(slotViewClicked()) ); + connect(mFileThumbnailView,SIGNAL(contextMenuRequested(QIconViewItem*,const QPoint&)), + this,SLOT(openContextMenu(QIconViewItem*,const QPoint&)) ); + connect(mFileThumbnailView,SIGNAL(dropped(QDropEvent*,KFileItem*)), + this,SLOT(openDropURLMenu(QDropEvent*, KFileItem*)) ); + connect(mFileThumbnailView, SIGNAL(doubleClicked(QIconViewItem*)), + this, SLOT(slotViewDoubleClicked()) ); + connect(mFileThumbnailView, SIGNAL(selectionChanged()), + this, SIGNAL(selectionChanged()) ); + + // Thumbnail details dialog + KAction* thumbnailDetailsDialogAction=new KAction(i18n("Edit Thumbnail Details..."), "configure", 0, mFileThumbnailView, SLOT(showThumbnailDetailsDialog()), actionCollection, "thumbnail_details_dialog"); + connect(mBottomThumbnailMode, SIGNAL(toggled(bool)), + thumbnailDetailsDialogAction, SLOT(setEnabled(bool)) ); + + // Fill toolbar + mListMode->plug(d->mToolBar); + mSideThumbnailMode->plug(d->mToolBar); + mBottomThumbnailMode->plug(d->mToolBar); + d->mToolBar->insertSeparator(); + sliderAction->plug(d->mToolBar); + d->mToolBar->insertSeparator(); + thumbnailDetailsDialogAction->plug(d->mToolBar); + + int id=d->mToolBar->insertWidget(-1, 0, d->mFilterHBox); + d->mToolBar->alignItemRight(id, true); + + mShowDotFiles->setChecked(FileViewConfig::showDotFiles()); + + bool startWithThumbnails=FileViewConfig::startWithThumbnails(); + setMode(startWithThumbnails?THUMBNAIL:FILE_LIST); + mSizeSlider->setEnabled(startWithThumbnails); + + if (startWithThumbnails) { + if (mFileThumbnailView->itemTextPos()==QIconView::Right) { + mSideThumbnailMode->setChecked(true); + } else { + mBottomThumbnailMode->setChecked(true); + } + // Make sure the thumbnail view and the slider tooltip are updated + updateThumbnailSize(mSizeSlider->value()); + mFileThumbnailView->startThumbnailUpdate(); + } else { + mListMode->setChecked(true); + } + thumbnailDetailsDialogAction->setEnabled(mBottomThumbnailMode->isChecked()); + + if (MiscConfig::rememberFilter()) { + d->loadFilterSettings(); + } + updateFromSettings(); +} + + +FileViewController::~FileViewController() { + // Save various settings + FileViewConfig::setStartWithThumbnails(mMode==THUMBNAIL); + + int filterMode = d->mFilterComboBox->currentItem(); + FileViewConfig::setFilterMode(filterMode); + + FileViewConfig::setShowFilterBar(d->mShowFilterBarCheckBox->isChecked()); + FileViewConfig::setNameFilter(d->mFilterBar->mNameEdit->text()); + FileViewConfig::setFromDateFilter(d->mFilterBar->mFromDateEdit->date()); + FileViewConfig::setToDateFilter(d->mFilterBar->mToDateEdit->date()); + + FileViewConfig::writeConfig(); + delete mDirLister; + delete d; +} + + +void FileViewController::setFocus() { + currentFileView()->widget()->setFocus(); +} + + +/** + * Do not let double click events propagate if Ctrl or Shift is down, to avoid + * toggling fullscreen + */ +bool FileViewController::eventFilter(QObject*, QEvent* event) { + if (event->type()!=QEvent::MouseButtonDblClick) return false; + + QMouseEvent* mouseEvent=static_cast(event); + if (mouseEvent->state() & Qt::ControlButton || mouseEvent->state() & Qt::ShiftButton) { + return true; + } + return false; +} + + +bool FileViewController::lastURLError() const { + return mDirLister->error(); +} + + +//----------------------------------------------------------------------- +// +// Public slots +// +//----------------------------------------------------------------------- +void FileViewController::setDirURL(const KURL& url) { + LOG(url.prettyURL()); + if ( mDirURL.equals(url,true) ) { + LOG("Same URL"); + return; + } + prefetchDone(); + mDirURL=url; + if (!KProtocolInfo::supportsListing(mDirURL)) { + LOG("Protocol does not support listing"); + return; + } + + mDirLister->clearError(); + currentFileView()->setShownFileItem(0L); + mFileNameToSelect=QString::null; + mDirLister->openURL(mDirURL); + emit urlChanged(mDirURL); + emit directoryChanged(mDirURL); + updateActions(); +} + + +/** + * Sets the file to select once the dir lister is done. If it's not running, + * immediatly selects the file. + */ +void FileViewController::setFileNameToSelect(const QString& fileName) { + mFileNameToSelect=fileName; + if (mDirLister->isFinished()) { + browseToFileNameToSelect(); + } +} + +void FileViewController::prefetch( KFileItem* item ) { + prefetchDone(); + if( item == NULL ) return; + mPrefetch = ImageLoader::loader( item->url(), this, BUSY_PRELOADING ); + connect( mPrefetch, SIGNAL( imageLoaded( bool )), SLOT( prefetchDone())); +} + +void FileViewController::prefetchDone() { + if( mPrefetch != NULL ) { + mPrefetch->release( this ); + mPrefetch = NULL; + } +} + +void FileViewController::slotSelectFirst() { + browseTo( findFirstImage()); + prefetch( findNextImage()); +} + +void FileViewController::slotSelectLast() { + browseTo(findLastImage()); + prefetch( findPreviousImage()); +} + +void FileViewController::slotSelectPrevious() { + browseTo(findPreviousImage()); + prefetch( findPreviousImage()); +} + +void FileViewController::slotSelectNext() { + browseTo(findNextImage()); + prefetch( findNextImage()); +} + +void FileViewController::slotSelectPreviousDir() { + mChangeDirStatus = CHANGE_DIR_STATUS_PREV; + mDirLister->clearError(); + mDirLister->openURL(mDirURL.upURL()); +} + +void FileViewController::slotSelectNextDir() { + mChangeDirStatus = CHANGE_DIR_STATUS_NEXT; + mDirLister->clearError(); + mDirLister->openURL(mDirURL.upURL()); +} + +void FileViewController::slotSelectFirstSubDir() { + KFileItem* item=currentFileView()->firstFileItem(); + while (item && !Archive::fileItemIsDirOrArchive(item)) { + item=currentFileView()->nextItem(item); + } + if (!item) { + LOG("No item found"); + return; + } + LOG("item->url(): " << item->url().prettyURL()); + KURL tmp=item->url(); + if (Archive::fileItemIsArchive(item)) { + tmp.setProtocol(Archive::protocolForMimeType(item->mimetype())); + } + tmp.adjustPath(1); + setDirURL(tmp); +} + + +void FileViewController::resetNameFilter() { + d->mFilterBar->mNameEdit->clear(); +} + + +void FileViewController::resetFromFilter() { + d->mFilterBar->mFromDateEdit->setDate(QDate()); +} + + +void FileViewController::resetToFilter() { + d->mFilterBar->mToDateEdit->setDate(QDate()); +} + + +void FileViewController::browseTo(KFileItem* item) { + prefetchDone(); + if (mBrowsing) return; + mBrowsing = true; + if (item) { + currentFileView()->setCurrentItem(item); + currentFileView()->clearSelection(); + currentFileView()->setSelected(item,true); + currentFileView()->ensureItemVisible(item); + if (!item->isDir() && !Archive::fileItemIsArchive(item)) { + emitURLChanged(); + } + } + updateActions(); + mBrowsing = false; +} + + +void FileViewController::browseToFileNameToSelect() { + // There's something to select + if (!mFileNameToSelect.isEmpty()) { + browseTo(findItemByFileName(mFileNameToSelect)); + mFileNameToSelect=QString::null; + return; + } + + // Nothing to select, but an item is already shown + if (currentFileView()->shownFileItem()) return; + + // Now we have to make some default choice + slotSelectFirst(); + + // If no item is selected, make sure the first one is + if (currentFileView()->selectedItems()->count()==0) { + KFileItem* item=currentFileView()->firstFileItem(); + if (item) { + currentFileView()->setCurrentItem(item); + currentFileView()->setSelected(item, true); + currentFileView()->ensureItemVisible(item); + } + } +} + + +void FileViewController::updateThumbnail(const KURL& url) { + if (mMode==FILE_LIST) return; + + KFileItem* item=mDirLister->findByURL(url); + if (!item) return; + mFileThumbnailView->updateThumbnail(item); +} + + +//----------------------------------------------------------------------- +// +// Private slots +// +//----------------------------------------------------------------------- +void FileViewController::slotViewExecuted() { + KFileItem* item=currentFileView()->currentFileItem(); + if (!item) return; + + bool isDir=item->isDir(); + bool isArchive=Archive::fileItemIsArchive(item); + if (isDir || isArchive) { + KURL tmp=url(); + + if (isArchive) { + tmp.setProtocol(Archive::protocolForMimeType(item->mimetype())); + } + tmp.adjustPath(1); + setDirURL(tmp); + } else { + emitURLChanged(); + } +} + + +void FileViewController::slotViewClicked() { + updateActions(); + KFileItem* item=currentFileView()->currentFileItem(); + if (!item || Archive::fileItemIsDirOrArchive(item)) return; + + mSelecting = true; + emitURLChanged(); + mSelecting = false; +} + + +void FileViewController::slotViewDoubleClicked() { + updateActions(); + KFileItem* item=currentFileView()->currentFileItem(); + if (item && !Archive::fileItemIsDirOrArchive(item)) emit imageDoubleClicked(); +} + + +void FileViewController::updateViewMode() { + if (mListMode->isChecked()) { + setMode(FILE_LIST); + return; + } + if (mSideThumbnailMode->isChecked()) { + mFileThumbnailView->setItemTextPos(QIconView::Right); + } else { + mFileThumbnailView->setItemTextPos(QIconView::Bottom); + } + + // Only switch the view if we are going from no thumbs to either side or + // bottom thumbs, not when switching between side and bottom thumbs + if (mMode==FILE_LIST) { + setMode(THUMBNAIL); + } else { + KFileItemList items=*mFileThumbnailView->items(); + KFileItem* shownFileItem=mFileThumbnailView->shownFileItem(); + + mFileThumbnailView->FileViewBase::clear(); + mFileThumbnailView->addItemList(items); + mFileThumbnailView->setShownFileItem(shownFileItem); + } + + updateThumbnailSize(mSizeSlider->value()); + mFileThumbnailView->startThumbnailUpdate(); +} + + +void FileViewController::updateThumbnailSize(int size) { + size*=SLIDER_RESOLUTION; + d->mSliderTracker->setText(i18n("Thumbnail size: %1x%2").arg(size).arg(size)); + FileViewConfig::setThumbnailSize(size); + mFileThumbnailView->setThumbnailSize(size); + Cache::instance()->checkThumbnailSize(size); +} + + +void FileViewController::toggleShowDotFiles() { + mDirLister->setShowingDotFiles(mShowDotFiles->isChecked()); + mDirLister->openURL(mDirURL); +} + + +void FileViewController::updateSortMenu(QDir::SortSpec _spec) { + int spec=_spec & (QDir::Name | QDir::Time | QDir::Size); + int item; + switch (spec) { + case QDir::Name: + item=0; + break; + case QDir::Time: + item=1; + break; + case QDir::Size: + item=2; + break; + default: + item=-1; + break; + } + d->mSortAction->setCurrentItem(item); +} + + +void FileViewController::setSorting() { + QDir::SortSpec spec; + + switch (d->mSortAction->currentItem()) { + case 0: // Name + spec=QDir::Name; + break; + case 1: // Date + spec=QDir::Time; + break; + case 2: // Size + spec=QDir::Size; + break; + default: + return; + } + if (d->mRevertSortAction->isChecked()) { + spec=QDir::SortSpec(spec | QDir::Reversed); + } + currentFileView()->setSorting(QDir::SortSpec(spec | QDir::DirsFirst)); + emit sortingChanged(); +} + + +//----------------------------------------------------------------------- +// +// Context menu +// +//----------------------------------------------------------------------- +void FileViewController::openContextMenu(KListView*,QListViewItem* item,const QPoint& pos) { + emit requestContextMenu(pos, item!=0); +} + + +void FileViewController::openContextMenu(QIconViewItem* item,const QPoint& pos) { + emit requestContextMenu(pos, item!=0); +} + + +//----------------------------------------------------------------------- +// +// Drop URL menu +// +//----------------------------------------------------------------------- +void FileViewController::openDropURLMenu(QDropEvent* event, KFileItem* item) { + KURL dest; + + if (item) { + dest=item->url(); + } else { + dest=mDirURL; + } + + KURL::List urls; + if (!KURLDrag::decode(event,urls)) return; + + FileOperation::openDropURLMenu(d->mStack, urls, dest); +} + + +//----------------------------------------------------------------------- +// +// File operations +// +//----------------------------------------------------------------------- +KURL::List FileViewController::selectedURLs() const { + KURL::List list; + + KFileItemListIterator it( *currentFileView()->selectedItems() ); + for ( ; it.current(); ++it ) { + list.append(it.current()->url()); + } + if (list.isEmpty()) { + const KFileItem* item=currentFileView()->shownFileItem(); + if (item) list.append(item->url()); + } + return list; +} + + +KURL::List FileViewController::selectedImageURLs() const { + KURL::List list; + + KFileItemListIterator it( *currentFileView()->selectedItems() ); + for ( ; it.current(); ++it ) { + KFileItem* item=it.current(); + if (!Archive::fileItemIsDirOrArchive(item)) { + list.append(item->url()); + } + } + if (list.isEmpty()) { + const KFileItem* item=currentFileView()->shownFileItem(); + if (item && !Archive::fileItemIsDirOrArchive(item)) list.append(item->url()); + } + return list; +} + + +//----------------------------------------------------------------------- +// +// Properties +// +//----------------------------------------------------------------------- +QString FileViewController::fileName() const { + KFileItem* item=currentFileView()->currentFileItem(); + if (!item) return ""; + return item->text(); +} + + +FileViewBase* FileViewController::currentFileView() const { + if (mMode==FILE_LIST) { + return mFileDetailView; + } else { + return mFileThumbnailView; + } +} + + +uint FileViewController::fileCount() const { + uint count=currentFileView()->count(); + + KFileItem* item=currentFileView()->firstFileItem(); + while (item && Archive::fileItemIsDirOrArchive(item)) { + item=currentFileView()->nextItem(item); + count--; + } + return count; +} + + +int FileViewController::shownFilePosition() const { + KFileItem* shownItem=currentFileView()->shownFileItem(); + if (!shownItem) return -1; + KFileItem* item=currentFileView()->firstFileItem(); + int position=0; + for (; + item && item!=shownItem; + item=currentFileView()->nextItem(item) ) + { + if (!Archive::fileItemIsDirOrArchive(item)) ++position; + } + return position; +} + + +KURL FileViewController::url() const { + KFileItem* item=currentFileView()->currentFileItem(); + if (!item) return mDirURL; + return item->url(); +} + +KURL FileViewController::dirURL() const { + return mDirURL; +} + + +uint FileViewController::selectionSize() const { + const KFileItemList* selectedItems=currentFileView()->selectedItems(); + return selectedItems->count(); +} + + +void FileViewController::setMode(FileViewController::Mode mode) { + const KFileItemList* items; + FileViewBase* oldView; + FileViewBase* newView; + + mMode=mode; + + if (mMode==FILE_LIST) { + mFileThumbnailView->stopThumbnailUpdate(); + oldView=mFileThumbnailView; + newView=mFileDetailView; + } else { + oldView=mFileDetailView; + newView=mFileThumbnailView; + } + + bool wasFocused=oldView->widget()->hasFocus(); + // Show the new active view + d->mStack->raiseWidget(newView->widget()); + if (wasFocused) newView->widget()->setFocus(); + + // Fill the new view + newView->clear(); + newView->addItemList(*oldView->items()); + + // Set the new view to the same state as the old + items=oldView->selectedItems(); + for(KFileItemListIterator it(*items);it.current()!=0L;++it) { + newView->setSelected(it.current(), true); + } + newView->setShownFileItem(oldView->shownFileItem()); + newView->setCurrentItem(oldView->currentFileItem()); + + // Remove references to the old view from KFileItems + items=oldView->items(); + for(KFileItemListIterator it(*items);it.current()!=0L;++it) { + it.current()->removeExtraData(oldView); + } + + // Update sorting + newView->setSorting(oldView->sorting()); + + // Clear the old view + oldView->FileViewBase::clear(); +} + + +void FileViewController::updateFromSettings() { + applyFilter(); + mFileThumbnailView->setMarginSize(FileViewConfig::thumbnailMarginSize()); + mFileThumbnailView->setItemDetails(FileViewConfig::thumbnailDetails()); + currentFileView()->widget()->update(); +} + + +void FileViewController::setSilentMode( bool silent ) { + mDirLister->setCheck( !silent ); +} + + +void FileViewController::retryURL() { + mDirLister->clearError(); + mDirLister->openURL( url()); +} + + +//----------------------------------------------------------------------- +// +// Dir lister slots +// +//----------------------------------------------------------------------- +void FileViewController::dirListerDeleteItem(KFileItem* item) { + KFileItem* newShownItem=0L; + const KFileItem* shownItem=currentFileView()->shownFileItem(); + if (shownItem==item) { + newShownItem=findNextImage(); + if (!newShownItem) newShownItem=findPreviousImage(); + } + + currentFileView()->removeItem(item); + + if (shownItem==item) { + currentFileView()->setCurrentItem(newShownItem); + currentFileView()->setSelected(newShownItem, true); + if (newShownItem) { + emit urlChanged(newShownItem->url()); + } else { + emit urlChanged(KURL()); + } + } +} + + +void FileViewController::dirListerNewItems(const KFileItemList& items) { + LOG(""); + mThumbnailsNeedUpdate=true; + currentFileView()->addItemList(items); +} + + +void FileViewController::dirListerRefreshItems(const KFileItemList& list) { + LOG(""); + const KFileItem* item=currentFileView()->shownFileItem(); + KFileItemListIterator it(list); + for (; *it!=0L; ++it) { + currentFileView()->updateView(*it); + if (*it==item) { + emit shownFileItemRefreshed(item); + } + } +} + + +void FileViewController::refreshItems(const KURL::List& urls) { + LOG(""); + KFileItemList list; + for( KURL::List::ConstIterator it = urls.begin(); + it != urls.end(); + ++it ) { + KURL dir = *it; + dir.setFileName( QString::null ); + if( dir != mDirURL ) continue; + // TODO this could be quite slow for many images? + KFileItem* item = findItemByFileName( (*it).filename()); + if( item ) list.append( item ); + } + dirListerRefreshItems( list ); +} + + +void FileViewController::dirListerClear() { + currentFileView()->clear(); +} + + +void FileViewController::dirListerStarted() { + LOG(""); + mThumbnailsNeedUpdate=false; +} + + +void FileViewController::dirListerCompleted() { + LOG(""); + // Delay the code to be executed when the dir lister has completed its job + // to avoid crash in KDirLister (see bug #57991) + QTimer::singleShot(0,this,SLOT(delayedDirListerCompleted())); +} + + +void FileViewController::delayedDirListerCompleted() { + // The call to sort() is a work around to a bug which causes + // FileThumbnailView::firstFileItem() to return a wrong item. This work + // around is not in firstFileItem() because it's const and sort() is a non + // const method + if (mMode!=FILE_LIST) { + mFileThumbnailView->sort(mFileThumbnailView->sortDirection()); + } + + if (mChangeDirStatus != CHANGE_DIR_STATUS_NONE) { + KFileItem *item; + QString fileName = mDirURL.filename(); + for (item=currentFileView()->firstFileItem(); item; item=currentFileView()->nextItem(item) ) { + if (item->name() == fileName) { + if (mChangeDirStatus == CHANGE_DIR_STATUS_NEXT) { + do { + item=currentFileView()->nextItem(item); + } while (item && !Archive::fileItemIsDirOrArchive(item)); + } else { + do { + item=currentFileView()->prevItem(item); + } while (item && !Archive::fileItemIsDirOrArchive(item)); + } + break; + }; + } + mChangeDirStatus = CHANGE_DIR_STATUS_NONE; + if (!item) { + mDirLister->openURL(mDirURL); + } else { + KURL tmp=item->url(); + LOG("item->url(): " << item->url().prettyURL()); + if (Archive::fileItemIsArchive(item)) { + tmp.setProtocol(Archive::protocolForMimeType(item->mimetype())); + } + tmp.adjustPath(1); + setDirURL(tmp); + } + } else { + browseToFileNameToSelect(); + emit completed(); + + if (mMode!=FILE_LIST && mThumbnailsNeedUpdate) { + mFileThumbnailView->startThumbnailUpdate(); + } + } +} + + +void FileViewController::dirListerCanceled() { + if (mMode!=FILE_LIST) { + mFileThumbnailView->stopThumbnailUpdate(); + } + + browseToFileNameToSelect(); +} + + +void FileViewController::setShowFilterBar(bool value) { + d->mShowFilterBarCheckBox->setChecked(value); +} + + +void FileViewController::setFilterMode(int mode) { + d->mFilterComboBox->setCurrentItem(mode); +} + + +void FileViewController::setFilterName(const QString& name) { + d->mFilterBar->mNameEdit->setText(name); +} + + +void FileViewController::setFilterFromDate(const QDate& date) { + d->mFilterBar->mFromDateEdit->setDate(date); +} + + +void FileViewController::setFilterToDate(const QDate& date) { + d->mFilterBar->mToDateEdit->setDate(date); +} + + +void FileViewController::applyFilter() { + QStringList mimeTypes; + FilterMode filterMode = static_cast( d->mFilterComboBox->currentItem() ); + + if (FileViewConfig::showDirs()) { + mimeTypes << "inode/directory"; + mimeTypes += Archive::mimeTypes(); + } + + if (filterMode != VIDEOS_ONLY) { + mimeTypes += MimeTypeUtils::rasterImageMimeTypes(); + mimeTypes << "image/svg"; + } + + if (filterMode != IMAGES_ONLY) { + mimeTypes << "video/"; + } + + if (d->mShowFilterBarCheckBox->isChecked()) { + QString txt=d->mFilterBar->mNameEdit->text(); + QDate from=d->mFilterBar->mFromDateEdit->date(); + QDate to=d->mFilterBar->mToDateEdit->date(); + + mDirLister->setNameFilter(txt); + mDirLister->setDateFilter(from, to); + } else { + mDirLister->setNameFilter(QString::null); + mDirLister->setDateFilter(QDate(), QDate()); + } + + mDirLister->setShowingDotFiles(mShowDotFiles->isChecked()); + mDirLister->setMimeFilter(mimeTypes); + + // Find next item matching the filter if any, so that we can keep it + // current + KFileItem* item=currentFileView()->currentFileItem(); + for (; item; item=currentFileView()->nextItem(item)) { + if (mDirLister->itemMatchFilters(item)) { + mFileNameToSelect=item->name(); + break; + } + } + + mDirLister->openURL(mDirURL); +} + + +void FileViewController::updateActions() { + KFileItem* firstImage=findFirstImage(); + + // There isn't any image, no need to continue + if (!firstImage) { + mSelectFirst->setEnabled(false); + mSelectPrevious->setEnabled(false); + mSelectNext->setEnabled(false); + mSelectLast->setEnabled(false); + return; + } + + // We did not select any image, let's activate everything + KFileItem* currentItem=currentFileView()->currentFileItem(); + if (!currentItem || Archive::fileItemIsDirOrArchive(currentItem)) { + mSelectFirst->setEnabled(true); + mSelectPrevious->setEnabled(true); + mSelectNext->setEnabled(true); + mSelectLast->setEnabled(true); + return; + } + + // There is at least one image, and an image is selected, let's be precise + bool isFirst=currentItem==firstImage; + bool isLast=currentItem==findLastImage(); + + mSelectFirst->setEnabled(!isFirst); + mSelectPrevious->setEnabled(!isFirst); + mSelectNext->setEnabled(!isLast); + mSelectLast->setEnabled(!isLast); +} + + +void FileViewController::emitURLChanged() { + KFileItem* item=currentFileView()->currentFileItem(); + currentFileView()->setShownFileItem(item); + + // We use a tmp value because the signal parameter is a reference + KURL tmp=url(); + LOG("urlChanged: " << tmp.prettyURL()); + emit urlChanged(tmp); +} + +KFileItem* FileViewController::findFirstImage() const { + KFileItem* item=currentFileView()->firstFileItem(); + while (item && Archive::fileItemIsDirOrArchive(item)) { + item=currentFileView()->nextItem(item); + } + if (item) { + LOG("item->url(): " << item->url().prettyURL()); + } else { + LOG("No item found"); + } + return item; +} + +KFileItem* FileViewController::findLastImage() const { + KFileItem* item=currentFileView()->items()->getLast(); + while (item && Archive::fileItemIsDirOrArchive(item)) { + item=currentFileView()->prevItem(item); + } + return item; +} + +KFileItem* FileViewController::findPreviousImage() const { + KFileItem* item=currentFileView()->shownFileItem(); + if (!item) return 0L; + do { + item=currentFileView()->prevItem(item); + } while (item && Archive::fileItemIsDirOrArchive(item)); + return item; +} + +KFileItem* FileViewController::findNextImage() const { + KFileItem* item=currentFileView()->shownFileItem(); + if (!item) return 0L; + do { + item=currentFileView()->nextItem(item); + } while (item && Archive::fileItemIsDirOrArchive(item)); + return item; +} + +KFileItem* FileViewController::findItemByFileName(const QString& fileName) const { + KFileItem *item; + if (fileName.isEmpty()) return 0L; + for (item=currentFileView()->firstFileItem(); + item; + item=currentFileView()->nextItem(item) ) { + if (item->name()==fileName) return item; + } + + return 0L; +} + + +} // namespace diff --git a/src/gvcore/fileviewcontroller.h b/src/gvcore/fileviewcontroller.h new file mode 100644 index 0000000..773de57 --- /dev/null +++ b/src/gvcore/fileviewcontroller.h @@ -0,0 +1,256 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef FILEVIEWCONTROLLER_H +#define FILEVIEWCONTROLLER_H + +// Qt +#include +#include +#include + +// KDE +#include +#include +#include +#include + +#include "libgwenview_export.h" +class QIconViewItem; +class QListViewItem; +class QPopupMenu; + +class KAccel; +class KAction; +class KActionCollection; +class KConfig; +class KListView; +class KRadioAction; +class KToggleAction; + +namespace Gwenview { +class FileViewBase; +class FileDetailView; +class FileThumbnailView; +class ImageLoader; + + +class DirLister; + +class LIBGWENVIEW_EXPORT FileViewController : public QWidget { +Q_OBJECT + +public: + enum Mode { FILE_LIST, THUMBNAIL}; + enum FilterMode { ALL, IMAGES_ONLY, VIDEOS_ONLY }; + + FileViewController(QWidget* parent,KActionCollection*); + ~FileViewController(); + + // Properties + void setMode(Mode); + + QString fileName() const; + KURL url() const; + KURL dirURL() const; + uint fileCount() const; + int shownFilePosition() const; + + uint selectionSize() const; + + FileViewBase* currentFileView() const; + FileThumbnailView* fileThumbnailView() const { return mFileThumbnailView; } + + KAction* selectFirst() const { return mSelectFirst; } + KAction* selectLast() const { return mSelectLast; } + KAction* selectPrevious() const { return mSelectPrevious; } + KAction* selectNext() const { return mSelectNext; } + KAction* selectPreviousDir() const { return mSelectPreviousDir; } + KAction* selectNextDir() const { return mSelectNextDir; } + KAction* selectFirstSubDir() const { return mSelectFirstSubDir; } + KRadioAction* listMode() const { return mListMode; } + KRadioAction* sideThumbnailMode() const { return mSideThumbnailMode; } + KRadioAction* bottomThumbnailMode() const { return mBottomThumbnailMode; } + KToggleAction* showDotFiles() const { return mShowDotFiles; } + + KURL::List selectedURLs() const; + KURL::List selectedImageURLs() const; + /** + * If set to true, no error messages will be displayed. + */ + void setSilentMode( bool silent ); + /** + * Returns true if there was an error since last URL had been opened. + */ + bool lastURLError() const; + /** + * Tries to open again the active URL. Useful for showing error messages + * initially supressed by silent mode. + */ + void retryURL(); + + void refreshItems( const KURL::List& urls ); // used by a workaround in KIPIInterface + + virtual void setFocus(); + +public slots: + void setDirURL(const KURL&); + void setFileNameToSelect(const QString&); + + void slotSelectFirst(); + void slotSelectLast(); + void slotSelectPrevious(); + void slotSelectNext(); + void slotSelectPreviousDir(); + void slotSelectNextDir(); + void slotSelectFirstSubDir(); + + void updateThumbnail(const KURL&); + + void updateFromSettings(); + + void setShowFilterBar(bool); + // 'int' suck, but I don't want to #include fileviewconfig.h + void setFilterMode(int); + void setFilterName(const QString&); + void setFilterFromDate(const QDate&); + void setFilterToDate(const QDate&); + void applyFilter(); + +signals: + void urlChanged(const KURL&); + /** + * Used by DirPart to tell Konqueror to change directory + */ + void directoryChanged(const KURL&); + + void selectionChanged(); + void completed(); + void canceled(); + void imageDoubleClicked(); + void shownFileItemRefreshed(const KFileItem*); + void sortingChanged(); + void requestContextMenu(const QPoint& pos, bool onItem); + +private slots: + void delayedDirListerCompleted(); + + // Used to enter directories + void slotViewExecuted(); + + // Used to change the current image + void slotViewClicked(); + + void slotViewDoubleClicked(); + + // These two methods forward the context menu requests from either view to + // openContextMenu(const QPoint&); + void openContextMenu(KListView*, QListViewItem*, const QPoint&); + void openContextMenu(QIconViewItem*,const QPoint&); + + // Get called by the thumbnail mode actions + void updateViewMode(); + + // Get called by the thumbnail slider + void updateThumbnailSize(int); + + void toggleShowDotFiles(); + void setSorting(); + void updateSortMenu(QDir::SortSpec); + + // Dir lister slots + void dirListerDeleteItem(KFileItem* item); + void dirListerNewItems(const KFileItemList& items); + void dirListerRefreshItems(const KFileItemList&); + void dirListerClear(); + void dirListerStarted(); + void dirListerCanceled(); + void dirListerCompleted(); + + void openDropURLMenu(QDropEvent*, KFileItem*); + + void prefetchDone(); + + void resetNameFilter(); + void resetFromFilter(); + void resetToFilter(); + +private: + struct Private; + Private* d; + Mode mMode; + FileDetailView* mFileDetailView; + FileThumbnailView* mFileThumbnailView; + DirLister* mDirLister; + KURL mDirURL; + ImageLoader* mPrefetch; + + // Our actions + KAction* mSelectFirst; + KAction* mSelectLast; + KAction* mSelectPrevious; + KAction* mSelectNext; + KAction* mSelectPreviousDir; + KAction* mSelectNextDir; + KAction* mSelectFirstSubDir; + + KRadioAction* mListMode; + KRadioAction* mSideThumbnailMode; + KRadioAction* mBottomThumbnailMode; + + QSlider* mSizeSlider; + + KToggleAction* mShowDotFiles; + + // Temp data used by the dir lister + bool mThumbnailsNeedUpdate; + QString mFileNameToSelect; + enum ChangeDirStatusVals { + CHANGE_DIR_STATUS_NONE, + CHANGE_DIR_STATUS_PREV, + CHANGE_DIR_STATUS_NEXT + } mChangeDirStatus; + + bool mBrowsing; + bool mSelecting; + + /** + * Browse to the given item. Prevents multiple calls using mBrowsing. + */ + void browseTo(KFileItem* item); + + void browseToFileNameToSelect(); + void emitURLChanged(); + void updateActions(); + void prefetch( KFileItem* item ); + + KFileItem* findFirstImage() const; + KFileItem* findLastImage() const; + KFileItem* findPreviousImage() const; + KFileItem* findNextImage() const; + KFileItem* findItemByFileName(const QString& fileName) const; + + bool eventFilter(QObject*, QEvent*); +}; + + +} // namespace +#endif + diff --git a/src/gvcore/filterbar.ui b/src/gvcore/filterbar.ui new file mode 100644 index 0000000..461e9f7 --- /dev/null +++ b/src/gvcore/filterbar.ui @@ -0,0 +1,255 @@ + +FilterBar + + + FilterBar + + + + 0 + 0 + 809 + 30 + + + + + 5 + 5 + 0 + 0 + + + + + unnamed + + + 3 + + + + mResetNameCombo + + + + 0 + 0 + 0 + 0 + + + + + + + + + mNameEdit + + + Name + + + Filter files with wildcards, like *.png + + + + + spacer1_2_2_2_3 + + + Horizontal + + + Maximum + + + + 16 + 16 + + + + + + mResetFrom + + + + 0 + 0 + 0 + 0 + + + + + + + + + textLabel1_2 + + + + 0 + 5 + 0 + 0 + + + + From: + + + mFromDateEdit + + + + + mFromDateEdit + + + Only show files newer than or +equal to this date + + + + + spacer1_2_2_2_2 + + + Horizontal + + + Maximum + + + + 16 + 16 + + + + + + mResetTo + + + + 0 + 0 + 0 + 0 + + + + + + + + + textLabel2 + + + + 0 + 5 + 0 + 0 + + + + To: + + + mToDateEdit + + + + + mToDateEdit + + + Only show files older than or equal to this date + + + + + spacer1_2_2_2 + + + Horizontal + + + Maximum + + + + 16 + 16 + + + + + + mFilterButton + + + &Filter + + + + + spacer1_2_2 + + + Horizontal + + + Expanding + + + + 16 + 16 + + + + + + + + Gwenview::ClickLineEdit +
clicklineedit.h
+ + 100 + 20 + + 0 + + 1 + 0 + 0 + 0 + + image0 + clickMessage +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000002f949444154388db5943168dc6614c77f57343cc10d12dc20c1054e5b0e6ac875ea1dedd2ed0e3ad4e0a1052f860c69c7ae490a1d1bdc4c4d8752770a5d42132834834137f4a20b047a1e0a2ab8200f067d83411f44a03708d2413e3bcef9da42ddb7083ebdeff7fddfff7ddf6b2549c23246a3d12bae20922469b596e067f367afa228425f2ab9c9b1a5fd57102d95344d8967315aead9bab354fae8a747848140d712f615384f1267997909b8ae181c0322fcf2e40d3080be54e85af232c6960ba82b10a0762972302715e0127484f09a22ed0aad4f37b7c10b2f1e7806ce4d4ed4d7536801e293a510ff5c319f5960698dc7e086c764cb673004289aaada6bc0b6b4287aaad4e7b75fe1c1bdbc417584fedb3dc481ec48591c581607969d5b21938f5da0827a0df8dc50c85278702f0360733b623206afd3fc53f549f661ef7ec6deb71961d0673816702e36fbad1570ed123f2ecea09f6c0bd2a9400aec89103f553ef850f8ec4e04c0c31f72d40a82ac572c0e14392c9e2b41c7633206757204416dc8f75f17cc67066b02766e85c44f3d16cf2dd9a1aed47e51b1d3745f51a2eb82d70171042d7dbef9aa81f6ba1ec3f77c5c4f190c7c00ccf13f8101700145a4f1d49e9c43015c11fc50c05196d557b5ac5056c05e07c0233b52548564aacc678620f0e8f502d23f0dbb7733b23f02cc61850051af91b3d66380e81af46f78a40796641f265b1ed6060cdff5f14361f7ae92fe6eb8fd29a8b5785d21da0073fc778a6b9076c5e6478d777bf733e65365e766c83b4388ae5b3effb24faf17608d416bd8dc0a89ba50bd360256153ba0350c86b0733364efbb94dd2f32e27d8fc186db3437cb3046c1697c9d4f2b46630fd75973ddb454b4ae4e570b26db2e6130e0e18f398b996131836630094157d8dc8a984e0b8a524169be9781d3346da6541b96ad188e61f07e487a18628f9650883620ecc1681c35673996f4c51a703c8b41042f04695ba89b2b25c8799603c640661af5ae231425a42f2cf91bcdbb60c5ebf3f4bfc6250fe40ac14992b4fe17f055c3932469fd051dce4f49a767eff00000000049454e44ae426082 + + + + mResetNameCombo + mResetFrom + mFromDateEdit + mResetTo + mToDateEdit + mFilterButton + + +
diff --git a/src/gvcore/fullscreenbar.cpp b/src/gvcore/fullscreenbar.cpp new file mode 100644 index 0000000..fb837ec --- /dev/null +++ b/src/gvcore/fullscreenbar.cpp @@ -0,0 +1,171 @@ +// vim:set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Qt +#include +#include +#include +#include +#include + +// KDE +#include + +// Local +#include "fullscreenbar.moc" +namespace Gwenview { + + +const int FULLSCREEN_ICON_SIZE = 32; +const int FULLSCREEN_LABEL_RADIUS = 6; +// Intervals are in milliseconds +const int SLIDE_IN_INTERVAL = 4; +const int SLIDE_OUT_INTERVAL = 12; +// Step is in pixels +const int SLIDE_STEP = 4; + + +static void fillMask(QPainter& painter, const QRect& rect) { + painter.fillRect( + rect.left(), + rect.top(), + rect.width() - FULLSCREEN_LABEL_RADIUS, + rect.height(), + painter.brush()); + + painter.fillRect( + rect.right() - FULLSCREEN_LABEL_RADIUS + 1, + rect.top(), + FULLSCREEN_LABEL_RADIUS, + rect.height() - FULLSCREEN_LABEL_RADIUS, + painter.brush()); + + painter.drawPie( + rect.right() - 2*FULLSCREEN_LABEL_RADIUS + 1, + rect.bottom() - 2*FULLSCREEN_LABEL_RADIUS + 1, + FULLSCREEN_LABEL_RADIUS*2, FULLSCREEN_LABEL_RADIUS*2, + 0, -16*90); +} + + +enum BarState { OUT, SLIDING_OUT, SLIDING_IN, IN }; + + +struct FullScreenBar::Private { + QTimer mTimer; + BarState mState; + bool mFirstShow; +}; + + +FullScreenBar::FullScreenBar(QWidget* parent) +: KToolBar(parent, "FullScreenBar") { + d=new Private; + d->mState=OUT; + d->mFirstShow=true; + setIconSize(FULLSCREEN_ICON_SIZE); + setMovingEnabled(false); + + QColor bg=colorGroup().highlight(); + QColor fg=colorGroup().highlightedText(); + QPalette pal(palette()); + pal.setColor(QColorGroup::Background, bg); + pal.setColor(QColorGroup::Foreground, fg); + pal.setColor(QColorGroup::Button, bg); + pal.setColor(QColorGroup::ButtonText, fg); + setPalette(pal); + + // Timer + connect(&d->mTimer, SIGNAL(timeout()), this, SLOT(slotUpdateSlide()) ); +} + + +FullScreenBar::~FullScreenBar() { + delete d; +} + + +void FullScreenBar::resizeEvent(QResizeEvent* event) { + KToolBar::resizeEvent(event); + + // Create a mask + QPainter painter; + QBitmap mask(size(), true); + painter.begin(&mask); + painter.setBrush(Qt::white); + fillMask(painter, rect()); + painter.end(); + + setMask(mask); +} + + +void FullScreenBar::showEvent(QShowEvent* event) { + KToolBar::showEvent(event); + // Make sure the bar position corresponds to the OUT state + if (!d->mFirstShow) return; + d->mFirstShow=false; + move(0, -height()); + layout()->setResizeMode(QLayout::Fixed); +} + + +void FullScreenBar::slideIn() { + if (d->mState!=IN) { + d->mState=SLIDING_IN; + d->mTimer.start(SLIDE_IN_INTERVAL); + } +} + + +void FullScreenBar::slideOut() { + if (d->mState!=OUT) { + d->mState=SLIDING_OUT; + d->mTimer.start(SLIDE_OUT_INTERVAL); + } +} + + +void FullScreenBar::slotUpdateSlide() { + int pos=y(); + + switch (d->mState) { + case SLIDING_OUT: + pos-=SLIDE_STEP; + if (pos<=-height()) { + d->mState=OUT; + d->mTimer.stop(); + } + break; + case SLIDING_IN: + pos+=SLIDE_STEP; + if (pos>=0) { + pos=0; + d->mState=IN; + d->mTimer.stop(); + } + break; + default: + kdWarning() << k_funcinfo << "We should not get there\n"; + } + move(0, pos); +} + +} // namespace diff --git a/src/gvcore/fullscreenbar.h b/src/gvcore/fullscreenbar.h new file mode 100644 index 0000000..3eb1919 --- /dev/null +++ b/src/gvcore/fullscreenbar.h @@ -0,0 +1,56 @@ +// vim:set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef FULLSCREENBAR_H +#define FULLSCREENBAR_H + +// KDE +#include + +class QResizeEvent; +class QShowEvent; +class QString; + +namespace Gwenview { +class FullScreenBar : public KToolBar { +Q_OBJECT +public: + FullScreenBar(QWidget* parent); + ~FullScreenBar(); + + void slideIn(); + void slideOut(); + +protected: + virtual void resizeEvent(QResizeEvent*); + virtual void showEvent(QShowEvent*); + +private slots: + void slotUpdateSlide(); + +private: + class Private; + Private* d; +}; + +} // namespace +#endif /* FULLSCREENBAR_H */ + diff --git a/src/gvcore/fullscreenconfig.kcfg b/src/gvcore/fullscreenconfig.kcfg new file mode 100644 index 0000000..38dbc4e --- /dev/null +++ b/src/gvcore/fullscreenconfig.kcfg @@ -0,0 +1,16 @@ + + + + + + + true + + + + + %f - %n/%N +%c + + + diff --git a/src/gvcore/fullscreenconfig.kcfgc b/src/gvcore/fullscreenconfig.kcfgc new file mode 100644 index 0000000..74be809 --- /dev/null +++ b/src/gvcore/fullscreenconfig.kcfgc @@ -0,0 +1,7 @@ +File=fullscreenconfig.kcfg +ClassName=FullScreenConfig +NameSpace=Gwenview +Singleton=true +Mutators=true +IncludeFiles=gvcore/libgwenview_export.h +Visibility=LIBGWENVIEW_EXPORT diff --git a/src/gvcore/gimp.h b/src/gvcore/gimp.h new file mode 100644 index 0000000..0c92b51 --- /dev/null +++ b/src/gvcore/gimp.h @@ -0,0 +1,138 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* -*- c++ -*- + * gimp.h: Header for a Qt 3 plug-in for reading GIMP XCF image files + * Copyright (C) 2001 lignum Computing, Inc. + * + * This plug-in 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.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * These are the constants and functions I extracted from The GIMP source + * code. If the reader fails to work, this is probably the place to start + * looking for discontinuities. + */ + +// From GIMP "tile.h" v1.2 + +const uint TILE_WIDTH = 64; //!< Width of a tile in the XCF file. +const uint TILE_HEIGHT = 64; //!< Height of a tile in the XCF file. + +// From GIMP "paint_funcs.c" v1.2 + +const int RANDOM_TABLE_SIZE = 4096; //!< Size of dissolve random number table. +const int RANDOM_SEED = 314159265; //!< Seed for dissolve random number table. +const double EPSILON = 0.0001; //!< Roundup in alpha blending. + +// From GIMP "paint_funcs.h" v1.2 + +const uchar OPAQUE_OPACITY = 255; //!< Opaque value for 8-bit alpha component. + +// From GIMP "apptypes.h" v1.2 + +//! Basic GIMP image type. QImage converter may produce a deeper image +//! than is specified here. For example, a grayscale image with an +//! alpha channel must (currently) use a 32-bit Qt image. + +typedef enum +{ + RGB, + GRAY, + INDEXED +} GimpImageBaseType; + +//! Type of individual layers in an XCF file. + +typedef enum +{ + RGB_GIMAGE, + RGBA_GIMAGE, + GRAY_GIMAGE, + GRAYA_GIMAGE, + INDEXED_GIMAGE, + INDEXEDA_GIMAGE +} GimpImageType; + +//! Effect to apply when layers are merged together. + +typedef enum +{ + NORMAL_MODE, + DISSOLVE_MODE, + BEHIND_MODE, + MULTIPLY_MODE, + SCREEN_MODE, + OVERLAY_MODE, + DIFFERENCE_MODE, + ADDITION_MODE, + SUBTRACT_MODE, + DARKEN_ONLY_MODE, + LIGHTEN_ONLY_MODE, + HUE_MODE, + SATURATION_MODE, + COLOR_MODE, + VALUE_MODE, + DIVIDE_MODE, + ERASE_MODE, + REPLACE_MODE, + ANTI_ERASE_MODE +} LayerModeEffects; + +// From GIMP "xcf.c" v1.2 + +//! Properties which can be stored in an XCF file. + +typedef enum +{ + PROP_END = 0, + PROP_COLORMAP = 1, + PROP_ACTIVE_LAYER = 2, + PROP_ACTIVE_CHANNEL = 3, + PROP_SELECTION = 4, + PROP_FLOATING_SELECTION = 5, + PROP_OPACITY = 6, + PROP_MODE = 7, + PROP_VISIBLE = 8, + PROP_LINKED = 9, + PROP_PRESERVE_TRANSPARENCY = 10, + PROP_APPLY_MASK = 11, + PROP_EDIT_MASK = 12, + PROP_SHOW_MASK = 13, + PROP_SHOW_MASKED = 14, + PROP_OFFSETS = 15, + PROP_COLOR = 16, + PROP_COMPRESSION = 17, + PROP_GUIDES = 18, + PROP_RESOLUTION = 19, + PROP_TATTOO = 20, + PROP_PARASITES = 21, + PROP_UNIT = 22, + PROP_PATHS = 23, + PROP_USER_UNIT = 24 +} PropType; + +// From GIMP "xcf.c" v1.2 + +//! Compression type used in layer tiles. + +typedef enum +{ + COMPRESS_NONE = 0, + COMPRESS_RLE = 1, + COMPRESS_ZLIB = 2, + COMPRESS_FRACTAL = 3 /* Unused. */ +} CompressionType; + + diff --git a/src/gvcore/imageframe.h b/src/gvcore/imageframe.h new file mode 100644 index 0000000..3825f06 --- /dev/null +++ b/src/gvcore/imageframe.h @@ -0,0 +1,42 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef IMAGEFRAME_H +#define IMAGEFRAME_H + +// Qt +#include +#include +namespace Gwenview { + +// Local + +struct ImageFrame { + ImageFrame( const QImage& i, int d ) : image( i ), delay( d ) {}; + ImageFrame() : delay( 0 ) {} // stupid Qt containers + QImage image; + int delay; // how long this frame should be shown in the animation +}; + +typedef QValueVector< ImageFrame > ImageFrames; + +} // namespace +#endif /* IMAGEFRAME_H */ + diff --git a/src/gvcore/imageloader.cpp b/src/gvcore/imageloader.cpp new file mode 100644 index 0000000..e1be4e8 --- /dev/null +++ b/src/gvcore/imageloader.cpp @@ -0,0 +1,917 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "imageloader.h" + +#include + +// Qt +#include +#include + +// KDE +#include +#include +#include + +// Local +#include "cache.h" +#include "miscconfig.h" +#include "imageutils/imageutils.h" +#include "imageutils/jpegcontent.h" + +#include "imageloader.moc" +namespace Gwenview { + +const unsigned int DECODE_CHUNK_SIZE=4096; + +/** Interval between image updates, in milli seconds */ +const int IMAGE_UPDATE_INTERVAL=100; + +#undef ENABLE_LOG +#undef LOG +#undef LOG2 + +#define ENABLE_LOG 0 + +#if ENABLE_LOG >= 1 +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +#if ENABLE_LOG >= 2 +#define LOG2(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG2(x) ; +#endif + +static QMap< KURL, ImageLoader* > sLoaders; + +//--------------------------------------------------------------------- +// +// CancellableBuffer +// This class acts like QBuffer, but will simulates a truncated file if the +// TSThread which was passed to its constructor has been asked for cancellation +// +//--------------------------------------------------------------------- +class CancellableBuffer : public QBuffer { +public: + CancellableBuffer(QByteArray buffer, TSThread* thread) + : QBuffer(buffer), mThread(thread) {} + + bool atEnd() const { + if (mThread->testCancel()) { + LOG("cancel detected"); + return true; + } + return QBuffer::atEnd(); + } + + Q_LONG readBlock(char * data, Q_ULONG maxlen) { + if (mThread->testCancel()) { + LOG("cancel detected"); + return 0; + } + return QBuffer::readBlock(data, maxlen); + } + + Q_LONG readLine(char * data, Q_ULONG maxlen) { + if (mThread->testCancel()) { + LOG("cancel detected"); + return 0; + } + return QBuffer::readLine(data, maxlen); + } + + QByteArray readAll() { + if (mThread->testCancel()) { + LOG("cancel detected"); + return QByteArray(); + } + return QBuffer::readAll(); + } + + int getch() { + if (mThread->testCancel()) { + LOG("cancel detected"); + setStatus(IO_ReadError); + return -1; + } + return QBuffer::getch(); + } + +private: + TSThread* mThread; +}; + + +//--------------------------------------------------------------------- +// +// DecoderThread +// +//--------------------------------------------------------------------- +void DecoderThread::run() { + QMutexLocker locker(&mMutex); + LOG(""); + + // This block makes sure imageIO won't access the image after the signal + // has been posted + { + QImageIO imageIO; + + CancellableBuffer buffer(mRawData, this); + buffer.open(IO_ReadOnly); + imageIO.setIODevice(&buffer); + bool ok=imageIO.read(); + if (testCancel()) { + LOG("cancelled"); + return; + } + + if (!ok) { + LOG("failed"); + postSignal( this, SIGNAL(failed()) ); + return; + } + + LOG("succeeded"); + mImage=imageIO.image(); + } + + LOG("succeeded, emitting signal"); + postSignal( this, SIGNAL(succeeded()) ); +} + + +void DecoderThread::setRawData(const QByteArray& data) { + QMutexLocker locker(&mMutex); + mRawData=data.copy(); +} + + +QImage DecoderThread::popLoadedImage() { + QMutexLocker locker(&mMutex); + QImage img=mImage; + mImage=QImage(); + return img; +} + + + +//--------------------------------------------------------------------- +// +// ImageLoaderPrivate +// +//--------------------------------------------------------------------- +struct OwnerData { + const QObject* owner; + BusyLevel priority; +}; + +enum GetState { + GET_PENDING_STAT, // Stat has not been started + GET_STATING, // Stat has been started + GET_PENDING_GET, // Stat is done, get has not been started + GET_GETTING, // Get has been started + GET_DONE, // All data has been received +}; + + +enum DecodeState { + DECODE_WAITING, // No data to decode yet + DECODE_PENDING_THREADED_DECODING, // Waiting for all data to start threaded decoding + DECODE_THREADED_DECODING, // Threaded decoder is running + DECODE_INCREMENTAL_DECODING, // Incremental decoder is running + DECODE_INCREMENTAL_DECODING_DONE, // Incremental decoder is done + DECODE_CACHED, // Image has been obtained from cache, but raw data was missing. Wait for get to finish. + DECODE_DONE, // All done +}; + +class ImageLoaderPrivate { +public: + ImageLoaderPrivate(ImageLoader* impl) + : mDecodedSize(0) + , mGetState(GET_PENDING_STAT) + , mDecodeState(DECODE_WAITING) + , mDecoder(impl) + , mSuspended(false) + , mNextFrameDelay(0) + , mWasFrameData(false) + , mOrientation(ImageUtils::NOT_AVAILABLE) + , mURLKind(MimeTypeUtils::KIND_UNKNOWN) + {} + + // How many of the raw data we have already decoded + unsigned int mDecodedSize; + + GetState mGetState; + DecodeState mDecodeState; + + KURL mURL; + + // The file timestamp + QDateTime mTimestamp; + + // The raw data we get + QByteArray mRawData; + + // The async decoder and it's waking timer + QImageDecoder mDecoder; + QTimer mDecoderTimer; + + // The decoder thread + DecoderThread mDecoderThread; + + // A rect of recently loaded pixels that the rest of the application has + // not been notified about with the imageChanged() signal + QRect mLoadChangedRect; + + // The time since we last emitted the imageChanged() signal + QTime mTimeSinceLastUpdate; + + // Whether the loading should be suspended + bool mSuspended; + + // Delay used for next frame after it's finished decoding. + int mNextFrameDelay; + + bool mWasFrameData; + + QImage mProcessedImage; // image frame currently being decoded + + QRegion mLoadedRegion; // loaded parts of mProcessedImage + + ImageFrames mFrames; + + QCString mImageFormat; + + ImageUtils::Orientation mOrientation; + + QString mMimeType; + MimeTypeUtils::Kind mURLKind; + + QValueVector< OwnerData > mOwners; // loaders may be shared + + + void determineImageFormat() { + Q_ASSERT(mRawData.size()>0); + QBuffer buffer(mRawData); + buffer.open(IO_ReadOnly); + mImageFormat = QImageIO::imageFormat(&buffer); + } +}; + + +//--------------------------------------------------------------------- +// +// ImageLoader +// +//--------------------------------------------------------------------- +ImageLoader::ImageLoader() { + LOG(""); + d = new ImageLoaderPrivate(this); + connect( BusyLevelManager::instance(), SIGNAL( busyLevelChanged(BusyLevel)), + this, SLOT( slotBusyLevelChanged(BusyLevel))); +} + + +ImageLoader::~ImageLoader() { + LOG(""); + if (d->mDecoderThread.running()) { + d->mDecoderThread.cancel(); + d->mDecoderThread.wait(); + } + delete d; +} + + +void ImageLoader::setURL( const KURL& url ) { + assert( d->mURL.isEmpty()); + d->mURL = url; +} + +void ImageLoader::startLoading() { + d->mTimestamp = Cache::instance()->timestamp( d->mURL ); + slotBusyLevelChanged( BusyLevelManager::instance()->busyLevel()); + + connect(&d->mDecoderTimer, SIGNAL(timeout()), this, SLOT(decodeChunk()) ); + + connect(&d->mDecoderThread, SIGNAL(succeeded()), + this, SLOT(slotDecoderThreadSucceeded()) ); + connect(&d->mDecoderThread, SIGNAL(failed()), + this, SLOT(slotDecoderThreadFailed()) ); + + checkPendingStat(); +} + +void ImageLoader::checkPendingStat() { + if( d->mSuspended || d->mGetState != GET_PENDING_STAT ) return; + + KIO::Job* job=KIO::stat( d->mURL, false ); + job->setWindow(KApplication::kApplication()->mainWidget()); + connect(job, SIGNAL(result(KIO::Job*)), + this, SLOT(slotStatResult(KIO::Job*)) ); + d->mGetState = GET_STATING; +} + +void ImageLoader::slotStatResult(KIO::Job* job) { + LOG("error code: " << job->error()); + + // Get modification time of the original file + KIO::UDSEntry entry = static_cast(job)->statResult(); + KIO::UDSEntry::ConstIterator it= entry.begin(); + QDateTime urlTimestamp; + for (; it!=entry.end(); it++) { + if ((*it).m_uds == KIO::UDS_MODIFICATION_TIME) { + urlTimestamp.setTime_t( (*it).m_long ); + break; + } + } + + if( d->mTimestamp.isValid() && urlTimestamp == d->mTimestamp ) { + // We have the image in cache + LOG(d->mURL << ", We have the image in cache"); + d->mRawData = Cache::instance()->file( d->mURL ); + Cache::instance()->getFrames(d->mURL, &d->mFrames, &d->mImageFormat); + + if( !d->mFrames.isEmpty()) { + LOG("The image in cache can be used"); + d->mProcessedImage = d->mFrames[0].image; + emit sizeLoaded(d->mProcessedImage.width(), d->mProcessedImage.height()); + emit imageChanged(d->mProcessedImage.rect()); + + if (d->mRawData.isNull() && d->mImageFormat=="JPEG") { + // Raw data is needed for JPEG, wait for it to be downloaded + LOG("Wait for raw data to be downloaded"); + d->mDecodeState = DECODE_CACHED; + } else { + // We don't care about raw data + finish(true); + return; + } + } else { + // Image in cache is broken + LOG("The image in cache cannot be used"); + if( !d->mRawData.isNull()) { + LOG("Using cached raw data"); + // Raw data is ok, skip get step and decode it + d->mGetState = GET_DONE; + d->mTimeSinceLastUpdate.start(); + d->mDecoderTimer.start(0, false); + return; + } + } + } + + d->mTimestamp = urlTimestamp; + d->mRawData.resize(0); + d->mGetState = GET_PENDING_GET; + checkPendingGet(); +} + +void ImageLoader::checkPendingGet() { + if( d->mSuspended || d->mGetState != GET_PENDING_GET ) return; + + // Start loading the image + KIO::Job* getJob=KIO::get( d->mURL, false, false); + getJob->setWindow(KApplication::kApplication()->mainWidget()); + + connect(getJob, SIGNAL(data(KIO::Job*, const QByteArray&)), + this, SLOT(slotDataReceived(KIO::Job*, const QByteArray&)) ); + + connect(getJob, SIGNAL(result(KIO::Job*)), + this, SLOT(slotGetResult(KIO::Job*)) ); + + d->mTimeSinceLastUpdate.start(); + d->mGetState = GET_GETTING; +} + + +void ImageLoader::slotGetResult(KIO::Job* job) { + LOG("error code: " << job->error()); + if( job->error() != 0 ) { + // failed + finish( false ); + return; + } + + d->mGetState = GET_DONE; + + // Store raw data in cache + // Note: Cache will give high cost to non-JPEG raw data. + Cache::instance()->addFile( d->mURL, d->mRawData, d->mTimestamp ); + + + switch (d->mDecodeState) { + case DECODE_CACHED: + // image was in cache, but not raw data + finish( true ); + break; + + case DECODE_PENDING_THREADED_DECODING: + // Start the decoder thread if needed + startThread(); + break; + + default: + // Finish decoding if needed + if (!d->mDecoderTimer.isActive()) d->mDecoderTimer.start(0); + } +} + +// There is no way in KImageIO to get the mimeType from the image format. +// This function assumes KImageIO::types and KImageIO::mimeTypes return items +// in the same order (which they do, according to the source code). +static QString mimeTypeFromFormat(const char* format) { + QStringList formats = KImageIO::types(KImageIO::Reading); + QStringList mimeTypes = KImageIO::mimeTypes(KImageIO::Reading); + int pos = formats.findIndex(QString::fromAscii(format)); + Q_ASSERT(pos != -1); + return mimeTypes[pos]; +} + +void ImageLoader::slotDataReceived(KIO::Job* job, const QByteArray& chunk) { + LOG2("size: " << chunk.size()); + if (chunk.size()<=0) return; + + int oldSize=d->mRawData.size(); + d->mRawData.resize(oldSize + chunk.size()); + memcpy(d->mRawData.data()+oldSize, chunk.data(), chunk.size() ); + + if (oldSize==0) { + // Try to determine the data type + QBuffer buffer(d->mRawData); + buffer.open(IO_ReadOnly); + const char* format = QImageIO::imageFormat(&buffer); + if (format) { + // This is a raster image, get the mime type now + d->mURLKind = MimeTypeUtils::KIND_RASTER_IMAGE; + d->mMimeType = mimeTypeFromFormat(format); + } else { + KMimeType::Ptr ptr = KMimeType::findByContent(d->mRawData); + d->mMimeType = ptr->name(); + d->mURLKind = MimeTypeUtils::mimeTypeKind(d->mMimeType); + } + if (d->mURLKind!=MimeTypeUtils::KIND_RASTER_IMAGE) { + Q_ASSERT(!d->mDecoderTimer.isActive()); + job->kill(true /* quietly */); + LOG("emit urlKindDetermined(!raster)"); + emit urlKindDetermined(); + return; + } + LOG("emit urlKindDetermined(raster)"); + emit urlKindDetermined(); + } + + // Decode the received data + if( !d->mDecoderTimer.isActive() && + (d->mDecodeState==DECODE_WAITING || d->mDecodeState==DECODE_INCREMENTAL_DECODING) + ) { + d->mDecoderTimer.start(0); + } +} + + +void ImageLoader::decodeChunk() { + if( d->mSuspended ) { + LOG("suspended"); + d->mDecoderTimer.stop(); + return; + } + + int chunkSize = QMIN(DECODE_CHUNK_SIZE, int(d->mRawData.size())-d->mDecodedSize); + int decodedSize = 0; + if (chunkSize>0) { + decodedSize = d->mDecoder.decode( + (const uchar*)(d->mRawData.data()+d->mDecodedSize), + chunkSize); + + if (decodedSize<0) { + // We can't use incremental decoding, switch to threaded decoding + d->mDecoderTimer.stop(); + if (d->mGetState == GET_DONE) { + startThread(); + } else { + d->mDecodeState = DECODE_PENDING_THREADED_DECODING; + } + return; + } + + // We just decoded some data + if (d->mDecodeState == DECODE_WAITING) { + d->mDecodeState = DECODE_INCREMENTAL_DECODING; + } + d->mDecodedSize+=decodedSize; + } + + if (decodedSize == 0) { + // We decoded as much as possible from the buffer, wait to receive + // more data before coming again in decodeChunk + d->mDecoderTimer.stop(); + + if (d->mGetState == GET_DONE) { + // All available data has been received. + if (d->mDecodeState == DECODE_INCREMENTAL_DECODING) { + // Decoder is not finished, the image must be truncated, + // let's simulate its end + kdWarning() << "ImageLoader::decodeChunk(): image '" << d->mURL.prettyURL() << "' is truncated.\n"; + + if (d->mProcessedImage.isNull()) { + d->mProcessedImage = d->mDecoder.image(); + } + emit imageChanged(d->mProcessedImage.rect()); + end(); + } + } + } +} + + +void ImageLoader::startThread() { + LOG("starting decoder thread"); + d->mDecodeState = DECODE_THREADED_DECODING; + d->mDecoderThread.setRawData(d->mRawData); + d->mDecoderThread.start(); +} + + +void ImageLoader::slotDecoderThreadFailed() { + LOG(""); + // Image can't be loaded + finish( false ); +} + + +void ImageLoader::slotDecoderThreadSucceeded() { + LOG(""); + d->mProcessedImage = d->mDecoderThread.popLoadedImage(); + d->mFrames.append( ImageFrame( d->mProcessedImage, 0 )); + emit sizeLoaded(d->mProcessedImage.width(), d->mProcessedImage.height()); + emit imageChanged(d->mProcessedImage.rect()); + finish(true); +} + + +/** + * Cache image and emit imageLoaded + */ +void ImageLoader::finish( bool ok ) { + LOG(""); + + d->mDecodeState = DECODE_DONE; + + if (!ok) { + d->mFrames.clear(); + d->mRawData = QByteArray(); + d->mImageFormat = QCString(); + d->mProcessedImage = QImage(); + emit imageLoaded( false ); + return; + } + + if (d->mImageFormat.isEmpty()) { + d->determineImageFormat(); + } + Q_ASSERT(d->mFrames.count() > 0); + Cache::instance()->addImage( d->mURL, d->mFrames, d->mImageFormat, d->mTimestamp ); + emit imageLoaded( true ); +} + + +BusyLevel ImageLoader::priority() const { + BusyLevel mylevel = BUSY_NONE; + for( QValueVector< OwnerData >::ConstIterator it = d->mOwners.begin(); + it != d->mOwners.end(); + ++it ) { + mylevel = QMAX( mylevel, (*it).priority ); + } + return mylevel; +} + +void ImageLoader::slotBusyLevelChanged( BusyLevel level ) { + // this loader may be needed for normal loading (BUSY_LOADING), or + // only for prefetching + BusyLevel mylevel = priority(); + if( level > mylevel ) { + suspendLoading(); + } else { + resumeLoading(); + } +} + +void ImageLoader::suspendLoading() { + d->mDecoderTimer.stop(); + d->mSuspended = true; +} + +void ImageLoader::resumeLoading() { + d->mSuspended = false; + d->mDecoderTimer.start(0, false); + checkPendingGet(); + checkPendingStat(); +} + + +//--------------------------------------------------------------------- +// +// QImageConsumer +// +//--------------------------------------------------------------------- +void ImageLoader::end() { + LOG(""); + + // Notify about the last loaded rectangle + LOG("mLoadChangedRect " << d->mLoadChangedRect); + if (!d->mLoadChangedRect.isEmpty()) { + emit imageChanged( d->mLoadChangedRect ); + } + + d->mDecoderTimer.stop(); + d->mDecodeState = DECODE_INCREMENTAL_DECODING_DONE; + + // We are done + if( d->mFrames.count() == 0 ) { + d->mFrames.append( ImageFrame( d->mProcessedImage, 0 )); + } + // The image has been totally decoded, we delay the call to finish because + // when we return from this function we will be in decodeChunk(), after the + // call to decode(), so we don't want to switch to a new impl yet, since + // this means deleting "this". + QTimer::singleShot(0, this, SLOT(callFinish()) ); +} + + +void ImageLoader::callFinish() { + finish(true); +} + + +void ImageLoader::changed(const QRect& constRect) { + LOG2(""); + QRect rect = constRect; + + if (d->mLoadedRegion.isEmpty()) { + // This is the first time we get called. Init mProcessedImage and emit + // sizeLoaded. + LOG("mLoadedRegion is empty"); + + // By default, mProcessedImage should use the image from mDecoder + d->mProcessedImage = d->mDecoder.image(); + + if (d->mImageFormat.isEmpty()) { + d->determineImageFormat(); + } + Q_ASSERT(!d->mImageFormat.isEmpty()); + if (d->mImageFormat == "JPEG") { + // This is a JPEG, extract orientation and adjust mProcessedImage + // if necessary according to misc options + ImageUtils::JPEGContent content; + + if (content.loadFromData(d->mRawData)) { + d->mOrientation = content.orientation(); + if (MiscConfig::autoRotateImages() && + d->mOrientation != ImageUtils::NOT_AVAILABLE && d->mOrientation != ImageUtils::NORMAL) { + QSize size = content.size(); + d->mProcessedImage = QImage(size, d->mDecoder.image().depth()); + } + d->mProcessedImage.setDotsPerMeterX(content.dotsPerMeterX()); + d->mProcessedImage.setDotsPerMeterY(content.dotsPerMeterY()); + } else { + kdWarning() << "ImageLoader::changed(): JPEGContent could not load '" << d->mURL.prettyURL() << "'\n"; + } + } + + LOG("emit sizeLoaded " << d->mProcessedImage.size()); + emit sizeLoaded(d->mProcessedImage.width(), d->mProcessedImage.height()); + } + + // Apply orientation if necessary and if wanted by user settings (misc options) + if (MiscConfig::autoRotateImages() && + d->mOrientation != ImageUtils::NOT_AVAILABLE && d->mOrientation != ImageUtils::NORMAL) { + // We can only rotate whole images, so copy the loaded rect in a temp + // image, rotate the temp image and copy it to mProcessedImage + + // Copy loaded rect + QImage temp(rect.size(), d->mProcessedImage.depth()); + bitBlt(&temp, 0, 0, + &d->mDecoder.image(), rect.left(), rect.top(), rect.width(), rect.height()); + + // Rotate + temp = ImageUtils::transform(temp, d->mOrientation); + + // Compute destination rect + QWMatrix matrix = ImageUtils::transformMatrix(d->mOrientation); + + QRect imageRect = d->mDecoder.image().rect(); + imageRect = matrix.mapRect(imageRect); + + rect = matrix.mapRect(rect); + rect.moveBy(-imageRect.left(), -imageRect.top()); + + // copy temp to mProcessedImage + bitBlt(&d->mProcessedImage, rect.left(), rect.top(), + &temp, 0, 0, temp.width(), temp.height()); + } + + // Update state tracking vars + d->mWasFrameData = true; + d->mLoadChangedRect |= rect; + d->mLoadedRegion |= rect; + if( d->mTimeSinceLastUpdate.elapsed() > IMAGE_UPDATE_INTERVAL ) { + LOG("emitting imageChanged " << d->mLoadChangedRect); + d->mTimeSinceLastUpdate.start(); + emit imageChanged(d->mLoadChangedRect); + d->mLoadChangedRect = QRect(); + } +} + +void ImageLoader::frameDone() { + frameDone( QPoint( 0, 0 ), d->mDecoder.image().rect()); +} + +void ImageLoader::frameDone(const QPoint& offset, const QRect& rect) { + LOG(""); + // Another case where the image loading in Qt's is a bit borken. + // It's possible to get several notes about a frame being done for one frame (with MNG). + if( !d->mWasFrameData ) { + // To make it even more fun, with MNG the sequence is actually + // setFramePeriod( 0 ) + // frameDone() + // setFramePeriod( delay ) + // frameDone() + // Therefore ignore the second frameDone(), but fix the delay that should be + // after the frame. + if( d->mFrames.count() > 0 ) { + d->mFrames.last().delay = d->mNextFrameDelay; + d->mNextFrameDelay = 0; + } + return; + } + d->mWasFrameData = false; + if( !d->mLoadChangedRect.isEmpty()) { + emit imageChanged(d->mLoadChangedRect); + d->mLoadChangedRect = QRect(); + d->mTimeSinceLastUpdate.start(); + } + d->mLoadedRegion = QRegion(); + + QImage image; + if (d->mProcessedImage.isNull()) { + image = d->mDecoder.image().copy(); + } else { + image = d->mProcessedImage.copy(); + } + + if( offset != QPoint( 0, 0 ) || rect != image.rect()) { + // Blit last frame below 'image' + if( !d->mFrames.isEmpty()) { + QImage im = d->mFrames.last().image.copy(); + bitBlt( &im, offset.x(), offset.y(), &image, rect.x(), rect.y(), rect.width(), rect.height()); + image = im; + } + } + d->mFrames.append( ImageFrame( image, d->mNextFrameDelay )); + d->mNextFrameDelay = 0; +} + +void ImageLoader::setLooping(int) { +} + +void ImageLoader::setFramePeriod(int milliseconds) { + if( milliseconds < 0 ) milliseconds = 0; // -1 means showing immediately + if( d->mNextFrameDelay == 0 || milliseconds != 0 ) { + d->mNextFrameDelay = milliseconds; + } +} + +void ImageLoader::setSize(int, int) { + // Do nothing, size is handled when ::changed() is called for the first + // time +} + + +QImage ImageLoader::processedImage() const { + return d->mProcessedImage; +} + + +ImageFrames ImageLoader::frames() const { + return d->mFrames; +} + + +QCString ImageLoader::imageFormat() const { + return d->mImageFormat; +} + + +QByteArray ImageLoader::rawData() const { + return d->mRawData; +} + + +QString ImageLoader::mimeType() const { + return d->mMimeType; +} + + +MimeTypeUtils::Kind ImageLoader::urlKind() const { + return d->mURLKind; +} + + +KURL ImageLoader::url() const { + return d->mURL; +} + + +QRegion ImageLoader::loadedRegion() const { + return d->mLoadedRegion; +} + + +bool ImageLoader::completed() const { + return d->mDecodeState == DECODE_DONE; +} + + +void ImageLoader::ref( const QObject* owner, BusyLevel priority ) { + OwnerData data; + data.owner = owner; + data.priority = priority; + d->mOwners.append( data ); + connect( owner, SIGNAL( destroyed()), SLOT( ownerDestroyed())); +} + +void ImageLoader::deref( const QObject* owner ) { + for( QValueVector< OwnerData >::Iterator it = d->mOwners.begin(); + it != d->mOwners.end(); + ++it ) { + if( (*it).owner == owner ) { + d->mOwners.erase( it ); + if( d->mOwners.count() == 0 ) { + sLoaders.remove( d->mURL ); + delete this; + } + return; + } + } + assert( false ); +} + +void ImageLoader::release( const QObject* owner ) { + disconnect( owner ); + deref( owner ); +} + +void ImageLoader::ownerDestroyed() { + deref( sender()); +} + +//--------------------------------------------------------------------- +// +// Managing loaders +// +//--------------------------------------------------------------------- + +ImageLoader* ImageLoader::loader( const KURL& url, const QObject* owner, BusyLevel priority ) { + if( sLoaders.contains( url )) { + ImageLoader* loader = sLoaders[ url ]; + loader->ref( owner, priority ); + // resume if this owner has high priority + loader->slotBusyLevelChanged( BusyLevelManager::instance()->busyLevel()); + return loader; + } + ImageLoader* loader = new ImageLoader; + loader->ref( owner, priority ); + sLoaders[ url ] = loader; + loader->setURL( url ); + // Code using a loader first calls loader() to get ImageLoader* and only after that it can + // connect to its signals etc., so don't start loading immediately. + // This also helps with preloading jobs, since BUSY_LOADING busy level is not entered immediately + // when a new picture is selected, so preloading jobs without this delay could start working + // immediately. + QTimer::singleShot( priority >= BUSY_LOADING ? 0 : 10, loader, SLOT( startLoading())); + return loader; +} + +} // namespace diff --git a/src/gvcore/imageloader.h b/src/gvcore/imageloader.h new file mode 100644 index 0000000..c1cc1ec --- /dev/null +++ b/src/gvcore/imageloader.h @@ -0,0 +1,123 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef IMAGELOADER_H +#define IMAGELOADER_H + +// Qt +#include +#include +#include + +// KDE +#include + +// Local +#include "tsthread/tsthread.h" +#include "imageframe.h" +#include "busylevelmanager.h" +#include "mimetypeutils.h" + +#include "libgwenview_export.h" +namespace Gwenview { +class DecoderThread : public TSThread { +Q_OBJECT +public: + void setRawData(const QByteArray&); + QImage popLoadedImage(); + +signals: + void failed(); + void succeeded(); + +protected: + void run(); + +private: + QMutex mMutex; + QByteArray mRawData; + QImage mImage; +}; + +class ImageLoaderPrivate; + +class LIBGWENVIEW_EXPORT ImageLoader : public QObject, public QImageConsumer { +Q_OBJECT +public: + static ImageLoader* loader( const KURL& url, const QObject* owner, BusyLevel priority ); // use this instead of ctor + void release( const QObject* owner ); // use this instead of dtor + + QImage processedImage() const; + ImageFrames frames() const; + QCString imageFormat() const; + QByteArray rawData() const; + QString mimeType() const; + MimeTypeUtils::Kind urlKind() const; + KURL url() const; + QRegion loadedRegion() const; // valid parts of processedImage() + bool completed() const; + +signals: + void urlKindDetermined(); + void sizeLoaded(int, int); + void imageChanged(const QRect&); + void imageLoaded( bool ok ); + +private slots: + void slotStatResult(KIO::Job*); + void slotDataReceived(KIO::Job*, const QByteArray& chunk); + void slotGetResult(KIO::Job*); + void decodeChunk(); + void slotDecoderThreadFailed(); + void slotDecoderThreadSucceeded(); + void slotBusyLevelChanged( BusyLevel ); + void ownerDestroyed(); + void startLoading(); + void callFinish(); + +private: + ImageLoader(); + ~ImageLoader(); + void ref( const QObject* owner, BusyLevel priority ); + void deref( const QObject* owner ); + void suspendLoading(); + void resumeLoading(); + void finish( bool ok ); + void startThread(); + void setURL( const KURL& url ); + void checkPendingStat(); + void checkPendingGet(); + BusyLevel priority() const; + + // QImageConsumer methods + void end(); + void changed(const QRect&); + void frameDone(); + void frameDone(const QPoint& offset, const QRect& rect); + void setLooping(int); + void setFramePeriod(int milliseconds); + void setSize(int, int); + + ImageLoaderPrivate* d; +}; + +} // namespace +#endif /* IMAGELOADER_H */ + diff --git a/src/gvcore/imagesavedialog.cpp b/src/gvcore/imagesavedialog.cpp new file mode 100644 index 0000000..f7405af --- /dev/null +++ b/src/gvcore/imagesavedialog.cpp @@ -0,0 +1,131 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Qt includes +#include + +// KDE includes +#include +#include +#include +#include +#include +#include + +// Our includes +#include "imagesavedialog.moc" +namespace Gwenview { + + +static int findFormatInFilterList(const QStringList& filters, const QString& format) { + int pos=0; + for(QStringList::const_iterator it=filters.begin(); it!=filters.end(); ++it,++pos) { + QStringList list=QStringList::split("|",*it); + if ( list[1].startsWith(format) ) return pos; + } + return -1; +} + + +ImageSaveDialog::ImageSaveDialog(KURL& url, const QCString& imageFormat, QWidget* parent) +: KFileDialog(":ImageSaveDialog",QString::null,parent,"imagesavedialog",true) +, mURL(url) +, mImageFormat(imageFormat) +{ + setOperationMode(KFileDialog::Saving); + + // FIXME: Ugly code to define the filter combo label. + KMimeType::List types; + setFilterMimeType(i18n("Format:"),types,KMimeType::mimeType("")); + + QStringList filters; + + // Create our filter list + QStringList mimeTypes=KImageIO::mimeTypes(); + for(QStringList::const_iterator it=mimeTypes.begin(); it!=mimeTypes.end(); ++it) { + QString format=KImageIO::typeForMime(*it); + + // Create the pattern part of the filter string + KMimeType::Ptr mt=KMimeType::mimeType(*it); + QStringList patterns; + for (QStringList::const_iterator patIt=mt->patterns().begin();patIt!=mt->patterns().end();++patIt) { + QString pattern=(*patIt).lower(); + if (!patterns.contains(pattern)) patterns.append(pattern); + } + if (patterns.isEmpty()) { + patterns.append( QString("*.%1").arg(format.lower()) ); + } + QString patternString=patterns.join(" "); + + // Create the filter string + QString filter=patternString + "|" + + format + " - " + mt->comment() + + " (" + patternString + ")"; + + // Add it to our list + filters.append(filter); + } + + qHeapSort(filters); + setFilter(filters.join("\n")); + + // Select the default image format + int pos=findFormatInFilterList(filters,mImageFormat); + if (pos==-1) { + pos=findFormatInFilterList(filters,"PNG"); + mImageFormat="PNG"; + } + + filterWidget->setCurrentItem(pos); + + // Tweak the filter widget + filterWidget->setEditable(false); + + connect(filterWidget,SIGNAL(activated(const QString&)), + this,SLOT(updateImageFormat(const QString&)) ); + + // Call slotFilterChanged() to get the list filtered by the filter we + // selected. If we don't use a single shot, it leads to a crash :-/ + QTimer::singleShot(0,this,SLOT(slotFilterChanged())); +} + + +void ImageSaveDialog::accept() { + KFileDialog::accept(); + mURL=selectedURL(); +} + + +void ImageSaveDialog::updateImageFormat(const QString& text) { + QStringList list=QStringList::split(" ",text); + mImageFormat=list[0].local8Bit(); + + QString name=locationEdit->currentText(); + QString suffix=KImageIO::suffix(mImageFormat); + int dotPos=name.findRev('.'); + if (dotPos>-1) { + name=name.left(dotPos); + } + name.append('.').append(suffix); + locationEdit->setCurrentText(name); +} + + +} // namespace diff --git a/src/gvcore/imagesavedialog.h b/src/gvcore/imagesavedialog.h new file mode 100644 index 0000000..6aba763 --- /dev/null +++ b/src/gvcore/imagesavedialog.h @@ -0,0 +1,53 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef IMAGESAVEDIALOG_H +#define IMAGESAVEDIALOG_H + +// KDE includes +#include + +class QString; +class QWidget; + +class KURL; + +namespace Gwenview { +class ImageSaveDialog : public KFileDialog { +Q_OBJECT +public: + ImageSaveDialog(KURL& url,const QCString& imageFormat,QWidget* parent); + QCString imageFormat() const { return mImageFormat; } + +protected slots: + void accept(); + +private slots: + void updateImageFormat(const QString&); + +private: + KURL& mURL; + QCString mImageFormat; + QMap mImageFormats; +}; + +} // namespace +#endif + diff --git a/src/gvcore/imageview.cpp b/src/gvcore/imageview.cpp new file mode 100644 index 0000000..f22b171 --- /dev/null +++ b/src/gvcore/imageview.cpp @@ -0,0 +1,1469 @@ +// vim:set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "config.h" + +#include "imageview.moc" + +#include +#include + +// Qt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "document.h" +#include "imageutils/imageutils.h" +#include "bcgdialog.h" +#include "busylevelmanager.h" +#include "imageviewtools.h" +#include "imageutils/croppedqimage.h" +#include "imageviewconfig.h" + +namespace Gwenview { + +/* + +Coordinates: + +The image can be zoomed, can have a position offset, and additionally there is +QScrollView's viewport. This means there are several coordinate systems. + + + +Let's start from simple things. Viewport ignored, zoom ignored: + + A----------------------------------- + | | + | | + | B--------------------- | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | ---------------------C | + | | + | | + ------------------------------------ + + +The inner rectangle is the image, outer rectangle is the widget. +A = [ 0, 0 ] +B = [ mXOffset, mYOffset ] +C = B + [ mDocument->width(), mDocument->height() ] + + + +The same, additionally the image is zoomed. + +A = [ 0, 0 ] +B = [ mXOffset, mYOffset ] +C = [ mZoom * mDocument->width(), mZoom * mDocument->height()) ] + +The groups of functions imageToWidget() and widgetToImage() do conversions +between the image and widget coordinates, i.e. imageToWidget() accepts coordinates +in the image (original,not zoomed,image's topleft corner is [0,0]) and returns +coordinates in the picture above, widgetToImage() works the other way around. + +There's no bounds checking, so widgetToImage( A ) in the example above would +return image coordinate with negative x,y. + +The widgetToImage() functions round the values (in order to have the conversion +as approximate as possible). However when converting from widget to image and back +this can result in the final rectangle being smaller than the original. +The widgetToImageBounding() function converts from widget to image coordinates +in a way which makes sure the reverse conversion will be at least as large +as the original geometry. + +There are no conversion functions for only width/height, as their conversion +depends on the position (because of the rounding etc.). For similar reasons +conversions should not be done with the bottomright corner of a rectangle, +but with the point next to it. + + + +For conversions from/to QScrollView's viewport, usually QScrollView methods should +be used: contentsX(), contentsY(), contentsWidth(), contentsHeight(), visibleWidth(), +visibleHeight(), contentsToViewport() and viewportToContents(). + +*/ + +const double MAX_ZOOM=16.0; // Same value as GIMP + +const int DEFAULT_MAX_REPAINT_SIZE = 10000; +const int LIMIT_MAX_REPAINT_SIZE = 10000000; + +#ifndef HAVE_LROUND +inline +long int lround( double x ) { + return static_cast< long int >( x >= 0 ? x + 0.5 : x - 0.5 ); +} +#endif + + +struct ImageView::Private { + Document* mDocument; + + Tools mTools; + + ToolID mToolID; + + // Offset to center images + int mXOffset, mYOffset; + + // Zoom info + ZoomMode mZoomMode; + double mZoom; + + // Gamma, brightness, contrast - multiplied by 100 + int mGamma, mBrightness, mContrast; + + // Our actions + QComboBox* mZoomCombo; + // We do not use KSelectAction because it's not possible to set the combo text + KWidgetAction* mZoomComboAction; + KToggleAction* mZoomToFit; + KToggleAction* mZoomToWidth; + KToggleAction* mZoomToHeight; + QValueVector mZoomComboActions; + KAction* mZoomIn; + KAction* mZoomOut; + KAction* mResetZoom; + KToggleAction* mLockZoom; + KAction* mAdjustBCG; + KAction* mIncreaseGamma; + KAction* mDecreaseGamma; + KAction* mIncreaseBrightness; + KAction* mDecreaseBrightness; + KAction* mIncreaseContrast; + KAction* mDecreaseContrast; + KActionCollection* mActionCollection; + BCGDialog* mBCGDialog; + + // Fullscreen stuff + bool mFullScreen; + + // Object state info + bool mOperaLikePrevious; // Flag to avoid showing the popup menu on Opera like previous + double mZoomBeforeAuto; + int mXCenterBeforeAuto, mYCenterBeforeAuto; + + QMap< long long, PendingPaint > mPendingPaints; + QRegion mPendingNormalRegion; + QRegion mPendingSmoothRegion; + int mPendingOperations; + QTimer mPendingPaintTimer; + bool mSmoothingSuspended; + QRegion mValidImageArea; + + int imageToWidgetX( int x ) const { + if( mZoom == 1.0 ) return x + mXOffset; + return lround( x * mZoom ) + mXOffset; + } + + int imageToWidgetY( int y ) const { + if( mZoom == 1.0 ) return y + mYOffset; + return lround( y * mZoom ) + mYOffset; + } + + QPoint imageToWidget( const QPoint& p ) const { + return QPoint( imageToWidgetX( p.x()), imageToWidgetY( p.y())); + } + + QRect imageToWidget( const QRect& r ) const { + return QRect( imageToWidget( r.topLeft()), + // don't use bottomright corner for conversion, but the one next to it + imageToWidget( r.bottomRight() + QPoint( 1, 1 )) - QPoint( 1, 1 )); + } + + int widgetToImageX( int x ) const { + if( mZoom == 1.0 ) return x - mXOffset; + return lround( ( x - mXOffset ) / mZoom ); + } + + int widgetToImageY( int y ) const { + if( mZoom == 1.0 ) return y - mYOffset; + return lround( ( y - mYOffset ) / mZoom ); + } + + QPoint widgetToImage( const QPoint& p ) const { + return QPoint( widgetToImageX( p.x()), widgetToImageY( p.y())); + } + + QRect widgetToImage( const QRect& r ) const { + return QRect( widgetToImage( r.topLeft()), + // don't use bottomright corner for conversion, but the one next to it + widgetToImage( r.bottomRight() + QPoint( 1, 1 )) - QPoint( 1, 1 )); + } + + QRect widgetToImageBounding( const QRect& r, int extra ) const { + QRect ret = widgetToImage( r ); + // make sure converting to image and back always returns QRect at least as large as 'r' + extra += mZoom == 1.0 ? 0 : int( ceil( 1 / mZoom )); + ret.addCoords( -extra, -extra, extra, extra ); + return ret; + } + + void initZoomCombo() { + mZoomCombo->clear(); + for (QValueVector::iterator it=mZoomComboActions.begin(); + it!=mZoomComboActions.end(); + ++it) + { + QString txt=(*it)->plainText(); + mZoomCombo->insertItem(txt); + } + + const double zoomValues[] = { 0.5, 1, 2 }; + int nbValues=sizeof(zoomValues) / sizeof(double); + for (int pos=0; posinsertItem(txt); + } + } +}; + + +inline bool doDelayedSmoothing() { + return ImageViewConfig::delayedSmoothing() + && ImageViewConfig::smoothAlgorithm()!=ImageUtils::SMOOTH_NONE; +} + + +class ImageView::EventFilter : public QObject { +public: + EventFilter(ImageView* parent) + : QObject(parent) {} + + bool eventFilter(QObject*, QEvent* event) { + switch (event->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::AccelOverride: + return static_cast< ImageView* >( parent()) + ->viewportKeyEvent(static_cast(event)); + default: + break; + } + return false; + } +}; + + + +ImageView::ImageView(QWidget* parent,Document* document, KActionCollection* actionCollection) +: QScrollView(parent,0L,WResizeNoErase|WRepaintNoErase|WPaintClever) +{ + d=new Private; + d->mDocument=document; + d->mToolID=SCROLL; + d->mXOffset=0; + d->mYOffset=0; + d->mZoomMode=static_cast( ImageViewConfig::zoomMode() ); + d->mZoom=1; + d->mActionCollection=actionCollection; + d->mFullScreen=false; + d->mOperaLikePrevious=false; + d->mZoomBeforeAuto=1; + d->mPendingOperations= 0 ; + d->mSmoothingSuspended= false ; + d->mGamma = 100; + d->mBrightness = 0; + d->mContrast = 100; + d->mBCGDialog = 0; + + viewport()->setFocusPolicy(WheelFocus); + setFrameStyle(NoFrame); + setAcceptDrops( true ); + viewport()->setAcceptDrops( true ); + + updateScrollBarMode(); + viewport()->setBackgroundColor(ImageViewConfig::backgroundColor() ); + + d->mTools[SCROLL]=new ScrollTool(this); + d->mTools[ZOOM]=new ZoomTool(this); + d->mTools[d->mToolID]->updateCursor(); + + // Create actions + d->mZoomToFit=new KToggleAction(i18n("Fit to &Window"),"viewmagfit",0,d->mActionCollection,"view_zoom_to_fit"); + connect(d->mZoomToFit,SIGNAL(toggled(bool)), + this,SLOT(setZoomToFit(bool)) ); + d->mZoomToWidth=new KToggleAction(i18n("Fit to &Width"),0,0,d->mActionCollection,"view_zoom_to_width"); + connect(d->mZoomToWidth,SIGNAL(toggled(bool)), + this,SLOT(setZoomToWidth(bool)) ); + d->mZoomToHeight=new KToggleAction(i18n("Fit to &Height"),0,0,d->mActionCollection,"view_zoom_to_height"); + connect(d->mZoomToHeight,SIGNAL(toggled(bool)), + this,SLOT(setZoomToHeight(bool)) ); + + d->mZoomIn=KStdAction::zoomIn(this,SLOT(slotZoomIn()),d->mActionCollection); + + d->mZoomOut=KStdAction::zoomOut(this,SLOT(slotZoomOut()),d->mActionCollection); + + d->mResetZoom=KStdAction::actualSize(this,SLOT(slotResetZoom()),d->mActionCollection); + d->mResetZoom->setIcon("viewmag1"); + + d->mLockZoom=new KToggleAction(i18n("&Lock Zoom"),"lock",0,d->mActionCollection,"view_zoom_lock"); + d->mLockZoom->setChecked(ImageViewConfig::lockZoom()); + connect(d->mLockZoom,SIGNAL(toggled(bool)), + this,SLOT(setLockZoom(bool)) ); + + d->mZoomCombo=new QComboBox(true); + // Avoid stealing focus + d->mZoomCombo->setFocusPolicy(ClickFocus); + connect(d->mZoomCombo, SIGNAL(activated(int)), + this, SLOT(slotSelectZoom()) ); + + d->mZoomComboAction=new KWidgetAction(d->mZoomCombo, i18n("Zoom"), 0, 0, 0, d->mActionCollection, "view_zoom_to"); + + d->mZoomComboActions.append(d->mZoomToFit); + d->mZoomComboActions.append(d->mZoomToWidth); + d->mZoomComboActions.append(d->mZoomToHeight); + if (d->mZoomMode!=ZOOM_FREE) { + d->mZoomComboActions[d->mZoomMode]->setChecked(true); + } + d->initZoomCombo(); + + d->mAdjustBCG=new KAction(i18n("Adjust Brightness/Contrast/Gamma"), "colorize", 0, + this, SLOT(showBCGDialog()), d->mActionCollection, "adjust_bcg"); + d->mIncreaseGamma=new KAction(i18n("Increase Gamma"),0,CTRL+Key_G, + this,SLOT(increaseGamma()),d->mActionCollection,"increase_gamma"); + d->mDecreaseGamma=new KAction(i18n("Decrease Gamma"),0,SHIFT+CTRL+Key_G, + this,SLOT(decreaseGamma()),d->mActionCollection,"decrease_gamma"); + d->mIncreaseBrightness=new KAction(i18n("Increase Brightness" ),0,CTRL+Key_B, + this,SLOT(increaseBrightness()),d->mActionCollection,"increase_brightness"); + d->mDecreaseBrightness=new KAction(i18n("Decrease Brightness" ),0,SHIFT+CTRL+Key_B, + this,SLOT(decreaseBrightness()),d->mActionCollection,"decrease_brightness"); + d->mIncreaseContrast=new KAction(i18n("Increase Contrast" ),0,CTRL+Key_C, + this,SLOT(increaseContrast()),d->mActionCollection,"increase_contrast"); + d->mDecreaseContrast=new KAction(i18n("Decrease Contrast" ),0,SHIFT+CTRL+Key_C, + this,SLOT(decreaseContrast()),d->mActionCollection,"decrease_contrast"); + + // Connect to some interesting signals + connect(d->mDocument,SIGNAL(loaded(const KURL&)), + this,SLOT(slotLoaded()) ); + + connect(d->mDocument,SIGNAL(loading()), + this,SLOT( loadingStarted()) ); + + connect(d->mDocument,SIGNAL(modified()), + this,SLOT(slotModified()) ); + + connect(d->mDocument, SIGNAL(sizeUpdated()), + this, SLOT(slotImageSizeUpdated()) ); + + connect(d->mDocument, SIGNAL(rectUpdated(const QRect&)), + this, SLOT(slotImageRectUpdated(const QRect&)) ); + + connect(&d->mPendingPaintTimer,SIGNAL(timeout()), + this,SLOT(checkPendingOperations()) ); + + connect(BusyLevelManager::instance(),SIGNAL(busyLevelChanged(BusyLevel)), + this,SLOT(slotBusyLevelChanged(BusyLevel) )); + + // This event filter is here to make sure the pixmap view is aware of the changes + // in the keyboard modifiers, even if it isn't focused. However, making this widget + // itself the filter would lead to doubled paint events, because QScrollView + // installs an event filter on its viewport, and doesn't filter out the paint + // events -> it'd get it twice, first from app filter, second from viewport filter. + EventFilter* filter=new EventFilter(this); + kapp->installEventFilter(filter); +} + + +ImageView::~ImageView() { + ImageViewConfig::setZoomMode(d->mZoomMode); + ImageViewConfig::setLockZoom(d->mLockZoom->isChecked()); + ImageViewConfig::self()->writeConfig(); + delete d->mTools[SCROLL]; + delete d->mTools[ZOOM]; + delete d; +} + + +void ImageView::slotLoaded() { + if (d->mDocument->isNull()) { + resizeContents(0,0); + viewport()->repaint(false); + return; + } + + if (doDelayedSmoothing()) scheduleOperation( SMOOTH_PASS ); +} + + +void ImageView::slotModified() { + if (d->mZoomMode!=ZOOM_FREE) { + updateZoom(d->mZoomMode); + } else { + updateContentSize(); + updateImageOffset(); + updateZoomActions(); + fullRepaint(); + } +} + + +void ImageView::loadingStarted() { + cancelPending(); + d->mSmoothingSuspended = true; + d->mValidImageArea = QRegion(); + d->mGamma = 100; + d->mBrightness = 0; + d->mContrast = 100; + + if (!d->mLockZoom->isChecked()) { + d->mZoomBeforeAuto = 1.; + } +} + +//------------------------------------------------------------------------ +// +// Properties +// +//------------------------------------------------------------------------ +double ImageView::zoom() const { + return d->mZoom; +} + + +bool ImageView::fullScreen() const { + return d->mFullScreen; +} + + +QPoint ImageView::offset() const { + return QPoint(d->mXOffset, d->mYOffset); +} + + +bool ImageView::canZoom(bool in) const { + KAction* zoomAction=in ? d->mZoomIn : d->mZoomOut; + return zoomAction->isEnabled(); +} + + +KToggleAction* ImageView::zoomToFit() const { + return d->mZoomToFit; +} + + +void ImageView::updateFromSettings() { + // Reset, so that next repaint doesn't possibly take longer because of + // smoothing + ImageViewConfig::setMaxRepaintSize(DEFAULT_MAX_REPAINT_SIZE); + ImageViewConfig::setMaxScaleRepaintSize(DEFAULT_MAX_REPAINT_SIZE); + ImageViewConfig::setMaxSmoothRepaintSize(DEFAULT_MAX_REPAINT_SIZE); + + if( doDelayedSmoothing() ) { + scheduleOperation( SMOOTH_PASS ); + } else { + fullRepaint(); + } + + // If enlargeSmallImage changed + if (d->mZoomMode!=ZOOM_FREE) { + updateZoom(d->mZoomMode); + } + + updateScrollBarMode(); + + if (!d->mFullScreen) { + viewport()->setBackgroundColor(ImageViewConfig::backgroundColor() ); + } +} + + +void ImageView::setZoom(double zoom, int centerX, int centerY) { + updateZoom(ZOOM_FREE, zoom, centerX, centerY); +} + + +void ImageView::updateZoom(ZoomMode zoomMode, double value, int centerX, int centerY) { + ZoomMode oldZoomMode = d->mZoomMode; + double oldZoom=d->mZoom; + d->mZoomMode=zoomMode; + KAction* checkedZoomAction=0; + + viewport()->setUpdatesEnabled(false); + + if (zoomMode==ZOOM_FREE) { + Q_ASSERT(value!=0); + d->mZoom=value; + } else { + if (oldZoomMode == ZOOM_FREE) { + // Only store zoom before auto if we were in ZOOM_FREE mode, otherwise + // we will store the computed auto zoom value (Bug 134590) + d->mZoomBeforeAuto = d->mZoom; + } + d->mXCenterBeforeAuto=width()/2 + contentsX() + d->mXOffset; + d->mYCenterBeforeAuto=height()/2 + contentsY() + d->mYOffset; + + if (zoomMode==ZOOM_FIT) { + d->mZoom=computeZoomToFit(); + checkedZoomAction=d->mZoomToFit; + + } else if (zoomMode==ZOOM_FIT_WIDTH) { + d->mZoom=computeZoomToWidth(); + checkedZoomAction=d->mZoomToWidth; + + } else { + d->mZoom=computeZoomToHeight(); + checkedZoomAction=d->mZoomToHeight; + } + } + + // Make sure only one zoom action is toggled on + d->mZoomToFit->setChecked( checkedZoomAction==d->mZoomToFit); + d->mZoomToWidth->setChecked( checkedZoomAction==d->mZoomToWidth); + d->mZoomToHeight->setChecked(checkedZoomAction==d->mZoomToHeight); + + updateContentSize(); + + // Find the coordinate of the center of the image + // and center the view on it + if (centerX==-1) { + centerX=int( ((visibleWidth()/2+contentsX()-d->mXOffset)/oldZoom)*d->mZoom ); + } + if (centerY==-1) { + centerY=int( ((visibleHeight()/2+contentsY()-d->mYOffset)/oldZoom)*d->mZoom ); + } + center(centerX,centerY); + + updateScrollBarMode(); + updateImageOffset(); + updateZoomActions(); + + viewport()->setUpdatesEnabled(true); + fullRepaint(); +} + + +void ImageView::setFullScreen(bool fullScreen) { + d->mFullScreen=fullScreen; + + if (d->mFullScreen) { + viewport()->setBackgroundColor(black); + } else { + viewport()->setBackgroundColor(ImageViewConfig::backgroundColor() ); + } +} + + +//------------------------------------------------------------------------ +// +// Overloaded methods +// +//------------------------------------------------------------------------ +void ImageView::resizeEvent(QResizeEvent* event) { + QScrollView::resizeEvent(event); + if (d->mZoomMode!=ZOOM_FREE) { + updateZoom(d->mZoomMode); + } else { + updateContentSize(); + updateImageOffset(); + } +} + + +inline void composite(uint* rgba,uint value) { + uint alpha=(*rgba) >> 24; + if (alpha<255) { + uint alphaValue=(255-alpha)*value; + + uint c1=( ( (*rgba & 0xFF0000) >> 16 ) * alpha + alphaValue ) >> 8; + uint c2=( ( (*rgba & 0x00FF00) >> 8 ) * alpha + alphaValue ) >> 8; + uint c3=( ( (*rgba & 0x0000FF) >> 0 ) * alpha + alphaValue ) >> 8; + *rgba=0xFF000000 + (c1<<16) + (c2<<8) + c3; + } +} + +void ImageView::drawContents(QPainter* painter,int clipx,int clipy,int clipw,int cliph) { + // Erase borders + QRect imageRect(0, 0, d->mDocument->width(), d->mDocument->height()); + imageRect = d->imageToWidget(imageRect); + + QRect widgetRect = QRect(0, 0, visibleWidth(), visibleHeight()); + + QRegion region = QRegion(widgetRect) - imageRect; + QMemArray rects = region.rects(); + for(unsigned int pos = 0; pos < rects.count(); ++pos ) { + painter->eraseRect(rects[pos]); + } + + // Repaint + if( !d->mValidImageArea.isEmpty()) { + addPendingPaint( false, QRect( clipx, clipy, clipw, cliph )); + } +} + +// How this pending stuff works: +// There's a queue of areas to paint (each with bool saying whether it's smooth pass). +// Also, there's a bitfield of pending operations, operations are handled only after +// there's nothing more to paint (so that smooth pass is started). +void ImageView::addPendingPaint( bool smooth, QRect rect ) { + if( d->mSmoothingSuspended && smooth ) return; + + // try to avoid scheduling already scheduled areas + QRegion& region = smooth ? d->mPendingSmoothRegion : d->mPendingNormalRegion; + if( region.intersect( rect ) == QRegion( rect )) + return; // whole rect has already pending paints + // at least try to remove the part that's already scheduled + rect = ( QRegion( rect ) - region ).boundingRect(); + region += rect; + if( rect.isEmpty()) + return; + addPendingPaintInternal( smooth, rect ); +} + +void ImageView::addPendingPaintInternal( bool smooth, QRect rect ) { + const long long MAX_DIM = 1000000; // if monitors get larger than this, we're in trouble :) + // QMap will ensure ordering (non-smooth first, top-to-bottom, left-to-right) + long long key = ( smooth ? MAX_DIM * MAX_DIM : 0 ) + rect.y() * MAX_DIM + rect.x(); + // handle the case of two different paints at the same position (just in case) + key *= 100; + bool insert = true; + while( d->mPendingPaints.contains( key )) { + if( d->mPendingPaints[ key ].rect.contains( rect )) { + insert = false; + break; + } + if( rect.contains( d->mPendingPaints[ key ].rect )) { + break; + } + ++key; + } + if( insert ) { + d->mPendingPaints[ key ] = PendingPaint( smooth, rect ); + } + scheduleOperation( CHECK_OPERATIONS ); +} + +void ImageView::checkPendingOperations() { + checkPendingOperationsInternal(); + if( d->mPendingPaints.isEmpty() && d->mPendingOperations == 0 ) { + d->mPendingPaintTimer.stop(); + } + updateBusyLevels(); +} + +void ImageView::limitPaintSize( PendingPaint& paint ) { + // The only thing that makes time spent in performPaint() vary + // is whether there will be scaling and whether there will be smoothing. + // So there are three max sizes for each mode. + int maxSize = ImageViewConfig::maxRepaintSize(); + if( d->mZoom != 1.0 ) { + if( paint.smooth || !doDelayedSmoothing() ) { + maxSize = ImageViewConfig::maxSmoothRepaintSize(); + } else { + maxSize = ImageViewConfig::maxScaleRepaintSize(); + } + } + // don't paint more than max_size pixels at a time + int maxHeight = ( maxSize + paint.rect.width() - 1 ) / paint.rect.width(); // round up + maxHeight = QMAX( maxHeight, 5 ); // at least 5 lines together + // can't repaint whole paint at once, adjust height and schedule the rest + if( maxHeight < paint.rect.height()) { + QRect remaining = paint.rect; + remaining.setTop( remaining.top() + maxHeight ); + addPendingPaintInternal( paint.smooth, remaining ); + paint.rect.setHeight( maxHeight ); + } +} + + +void ImageView::checkPendingOperationsInternal() { + if( !d->mPendingPaintTimer.isActive()) // suspended + return; + while( !d->mPendingPaints.isEmpty()) { + PendingPaint paint = *d->mPendingPaints.begin(); + d->mPendingPaints.remove( d->mPendingPaints.begin()); + limitPaintSize( paint ); // modifies paint.rect if necessary + QRegion& region = paint.smooth ? d->mPendingSmoothRegion : d->mPendingNormalRegion; + region -= paint.rect; + QRect visibleRect( contentsX(), contentsY(), visibleWidth(), visibleHeight()); + QRect paintRect = paint.rect.intersect( visibleRect ); + if( !paintRect.isEmpty()) { + QPainter painter( viewport()); + painter.translate( -contentsX(), -contentsY()); + performPaint( &painter, paintRect.x(), paintRect.y(), + paintRect.width(), paintRect.height(), paint.smooth ); + return; + } + } + if( d->mPendingOperations & SMOOTH_PASS ) { + d->mSmoothingSuspended = false; + if( doDelayedSmoothing() ) { + QRect visibleRect( contentsX(), contentsY(), visibleWidth(), visibleHeight()); + addPendingPaint( true, visibleRect ); + } + d->mPendingOperations &= ~SMOOTH_PASS; + return; + } +} + +void ImageView::scheduleOperation( Operation operation ) +{ + d->mPendingOperations |= operation; + slotBusyLevelChanged( BusyLevelManager::instance()->busyLevel()); + updateBusyLevels(); +} + +void ImageView::updateBusyLevels() { + if( !d->mPendingPaintTimer.isActive()) { + BusyLevelManager::instance()->setBusyLevel( this, BUSY_NONE ); + } else if( !d->mPendingPaints.isEmpty() && !(*d->mPendingPaints.begin()).smooth ) { + BusyLevelManager::instance()->setBusyLevel( this, BUSY_PAINTING ); + } else if(( d->mPendingOperations & SMOOTH_PASS ) + || ( !d->mPendingPaints.isEmpty() && (*d->mPendingPaints.begin()).smooth )) { + BusyLevelManager::instance()->setBusyLevel( this, BUSY_SMOOTHING ); + } else { + assert( false ); + } +} + +void ImageView::slotBusyLevelChanged( BusyLevel level ) { + bool resume = false; + if( level <= BUSY_PAINTING + && !d->mPendingPaints.isEmpty() && !(*d->mPendingPaints.begin()).smooth ) { + resume = true; + } else if( level <= BUSY_SMOOTHING + && (( d->mPendingOperations & SMOOTH_PASS ) + || ( !d->mPendingPaints.isEmpty() && (*d->mPendingPaints.begin()).smooth ))) { + resume = true; + } + if( resume ) { + d->mPendingPaintTimer.start( 0 ); + } else { + d->mPendingPaintTimer.stop(); + } +} + +// How to do painting: +// When something needs to be erased: QPainter on viewport and eraseRect() +// When whole picture needs to be repainted: fullRepaint() +// When a part of the picture needs to be updated: viewport()->repaint(area,false) +// All other paints will be changed to progressive painting. +void ImageView::fullRepaint() { + if( !viewport()->isUpdatesEnabled()) return; + cancelPending(); + viewport()->repaint(false); +} + +void ImageView::cancelPending() { + d->mPendingPaints.clear(); + d->mPendingNormalRegion = QRegion(); + d->mPendingSmoothRegion = QRegion(); + d->mPendingPaintTimer.stop(); + d->mPendingOperations = 0; + updateBusyLevels(); +} + +//#define DEBUG_RECTS + +// do the actual painting +void ImageView::performPaint( QPainter* painter, int clipx, int clipy, int clipw, int cliph, bool secondPass ) { + #ifdef DEBUG_RECTS + static QColor colors[4]={QColor(255,0,0),QColor(0,255,0),QColor(0,0,255),QColor(255,255,0) }; + static int numColor=0; + #endif + + QTime t; + t.start(); + + if (d->mDocument->isNull()) { + painter->eraseRect(clipx,clipy,clipw,cliph); + return; + } + + // True if another pass will follow + bool fastpass = doDelayedSmoothing() && zoom() != 1.0 && !secondPass; + + ImageUtils::SmoothAlgorithm smoothAlgo = ImageUtils::SMOOTH_NONE; + if( zoom() != 1.0 ) { + if (doDelayedSmoothing() && !secondPass) { + // Add a second, smoothing pass + addPendingPaint( true, QRect( clipx, clipy, clipw, cliph )); + } else { + // We need to smooth now + smoothAlgo = static_cast( ImageViewConfig::smoothAlgorithm() ); + } + } + + int extraPixels = ImageUtils::extraScalePixels( smoothAlgo, zoom()); + QRect imageRect = d->widgetToImageBounding( QRect(clipx,clipy,clipw,cliph), extraPixels ); + imageRect = imageRect.intersect( QRect( 0, 0, d->mDocument->width(), d->mDocument->height())); + QMemArray< QRect > rects = d->mValidImageArea.intersect( imageRect ).rects(); + for( unsigned int i = 1; i < rects.count(); ++i ) { + addPendingPaint( secondPass, d->imageToWidget( rects[ i ] )); + } + imageRect = rects.count() > 0 ? rects[ 0 ] : QRect(); + if (imageRect.isEmpty()) { + painter->eraseRect(clipx,clipy,clipw,cliph); + return; + } + QRect widgetRect = d->imageToWidget( imageRect ); + if (widgetRect.isEmpty() || imageRect.isEmpty()) { + painter->eraseRect(clipx,clipy,clipw,cliph); + return; + } + +// With very large images, just getting a subimage using QImage::copy( QRect ) takes a significant +// portion of time here (even though it's just copying of data - probably because it's a lot of data). +// So don't do any subimage copying but instead use CroppedQImage which just manipulates scanline +// pointers. Note however that it's a bit hackish and there may be trouble if any code accesses +// the image data directly as a whole. See CroppedQImage for details. + +// QImage image = d->mDocument->image().copy( imageRect ); + ImageUtils::CroppedQImage image( d->mDocument->image(), imageRect ); + + if( zoom() != 1.0 ) { + image=ImageUtils::scale(image,widgetRect.width(),widgetRect.height(), smoothAlgo ); + } + + if( d->mBrightness != 0 ) { + image.normalize(); // needed, it will be modified + image = ImageUtils::changeBrightness( image, d->mBrightness ); + } + + if( d->mContrast != 100 ) { // != 1.0 + image.normalize(); // needed, it will be modified + image = ImageUtils::changeContrast( image, d->mContrast ); + } + + if( d->mGamma != 100 ) { // != 1.0 + image.normalize(); // needed, it will be modified + image = ImageUtils::changeGamma( image, d->mGamma ); + } + +// Calling normalize() here would make image to be a proper QImage without modified scanlines, +// so that even calling QImage::copy() would work. However, it seems it's not necessary to call +// it here. The code above checks that QImage::copy() or similar doesn't occur (that zoom() != 1.0 +// is there primarily to avoid that). If any kind of redraw trouble occurs, try uncommenting this +// line below first. +// image.normalize(); // make it use its own data, if needed + + if (image.hasAlphaBuffer()) { + image.normalize(); // needed, it will be modified + if (image.depth()!=32) { + image=image.convertDepth(32); + } + + bool light; + + int imageXOffset=widgetRect.x()-d->mXOffset; + int imageYOffset=widgetRect.y()-d->mYOffset; + int imageWidth=image.width(); + int imageHeight=image.height(); + for (int y=0;ybackgroundColor()); + bufferPainter.eraseRect(0,0,paintRect.width(),paintRect.height()); + bufferPainter.drawImage(widgetRect.topLeft()-paintRect.topLeft(),image, + fastpass?ThresholdDither:0); + } + painter->drawPixmap(paintRect.topLeft(),buffer); + + if( paintRect.width() * paintRect.height() >= 10000 ) { // ignore small repaints + // try to do one step in 0.1sec + int size = paintRect.width() * paintRect.height() * 100 / QMAX( t.elapsed(), 1 ); + + int maxRepaintSize; + if (zoom() == 1.0) { + maxRepaintSize=ImageViewConfig::maxRepaintSize(); + } else { + if (smoothAlgo!=ImageUtils::SMOOTH_NONE) { + maxRepaintSize=ImageViewConfig::maxSmoothRepaintSize(); + } else { + maxRepaintSize=ImageViewConfig::maxScaleRepaintSize(); + } + } + + maxRepaintSize = KCLAMP( + ( size + maxRepaintSize ) / 2, + 10000, LIMIT_MAX_REPAINT_SIZE); + + if (zoom() == 1.0) { + ImageViewConfig::setMaxRepaintSize(maxRepaintSize); + } else { + if (smoothAlgo!=ImageUtils::SMOOTH_NONE) { + ImageViewConfig::setMaxSmoothRepaintSize(maxRepaintSize); + } else { + ImageViewConfig::setMaxScaleRepaintSize(maxRepaintSize); + } + } + } + + #ifdef DEBUG_RECTS + painter->setPen(colors[numColor]); + numColor=(numColor+1)%4; + painter->drawRect(paintRect); + #endif + + QApplication::flushX(); +} + + +void ImageView::viewportMousePressEvent(QMouseEvent* event) { + viewport()->setFocus(); + switch (event->button()) { + case Qt::LeftButton: + d->mTools[d->mToolID]->leftButtonPressEvent(event); + break; + case Qt::RightButton: + d->mTools[d->mToolID]->rightButtonPressEvent(event); + break; + default: // Avoid compiler complain + break; + } +} + + +void ImageView::viewportMouseMoveEvent(QMouseEvent* event) { + selectTool(event->state(), true); + d->mTools[d->mToolID]->mouseMoveEvent(event); +} + + +void ImageView::viewportMouseReleaseEvent(QMouseEvent* event) { + switch (event->button()) { + case Qt::LeftButton: + if (event->stateAfter() & Qt::RightButton) { + d->mOperaLikePrevious=true; + emit selectPrevious(); + return; + } + d->mTools[d->mToolID]->leftButtonReleaseEvent(event); + break; + + case Qt::MidButton: + d->mTools[d->mToolID]->midButtonReleaseEvent(event); + break; + + case Qt::RightButton: + if (event->stateAfter() & Qt::LeftButton) { + emit selectNext(); + return; + } + + if (d->mOperaLikePrevious) { // Avoid showing the popup menu after Opera like previous + d->mOperaLikePrevious=false; + } else { + d->mTools[d->mToolID]->rightButtonReleaseEvent(event); + } + break; + + default: // Avoid compiler complain + break; + } +} + + +bool ImageView::eventFilter(QObject* obj, QEvent* event) { + switch (event->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::AccelOverride: + return viewportKeyEvent(static_cast(event)); + + case QEvent::MouseButtonDblClick: + if (d->mToolID==ZOOM) return false; + emit doubleClicked(); + return true; + + // Getting/loosing focus causes repaints, but repainting here is expensive, + // and there's no need to repaint on focus changes, as the focus is not + // indicated. + case QEvent::FocusIn: + case QEvent::FocusOut: + return true; + + case QEvent::Enter: + selectTool( kapp->keyboardMouseState(), true ); + emitRequestHintDisplay(); + break; + + default: + break; + } + return QScrollView::eventFilter(obj,event); +} + + +bool ImageView::viewportKeyEvent(QKeyEvent* event) { + selectTool(event->stateAfter(), false); + return false; +} + + +void ImageView::contentsDragEnterEvent(QDragEnterEvent* event) { + event->accept( QUriDrag::canDecode( event )); +} + +void ImageView::contentsDropEvent(QDropEvent* event) { + KURL::List list; + if( KURLDrag::decode( event, list )) { + d->mDocument->setURL( list.first()); + } +} + +void ImageView::keyPressEvent( QKeyEvent *event ) { + QScrollView::keyPressEvent( event ); + int deltaX, deltaY; + + if (event->state() != Qt::NoButton) { + return; + } + switch (event->key()) { + case Key_Up: + deltaX = 0; + deltaY = -1; + break; + case Key_Down: + deltaX = 0; + deltaY = 1; + break; + case Key_Left: + deltaX = -1; + deltaY = 0; + break; + case Key_Right: + deltaX = 1; + deltaY = 0; + break; + default: + return; + } + deltaX *= width() / 2; + deltaY *= height() / 2; + scrollBy (deltaX, deltaY); +} + +/** + * If force is set, the cursor will be updated even if the tool is not + * different from the current one. + */ +void ImageView::selectTool(ButtonState state, bool force) { + ToolID oldToolID=d->mToolID; + if (state & ControlButton) { + d->mToolID=ZOOM; + if (d->mToolID!=oldToolID) { + emitRequestHintDisplay(); + } + } else { + d->mToolID=SCROLL; + } + + if (d->mToolID!=oldToolID || force) { + d->mTools[d->mToolID]->updateCursor(); + } +} + + +void ImageView::wheelEvent(QWheelEvent* event) { + d->mTools[d->mToolID]->wheelEvent(event); +} + + +//------------------------------------------------------------------------ +// +// Slots +// +//------------------------------------------------------------------------ +void ImageView::slotZoomIn() { + updateZoom(ZOOM_FREE, computeZoom(true)); +} + + +void ImageView::slotZoomOut() { + updateZoom(ZOOM_FREE, computeZoom(false)); +} + + +void ImageView::slotResetZoom() { + updateZoom(ZOOM_FREE, 1.0); +} + + +void ImageView::slotSelectZoom() { + int currentItem=d->mZoomCombo->currentItem(); + + if (currentItem>=int(d->mZoomComboActions.count()) ) { + QString txt=d->mZoomCombo->currentText(); + txt=txt.left(txt.find('%')); + double value=KGlobal::locale()->readNumber(txt) / 100.0; + updateZoom(ZOOM_FREE, value); + } else { + d->mZoomComboActions[currentItem]->activate(); + } +} + + +void ImageView::setZoomToFit(bool on) { + if (on) { + updateZoom(ZOOM_FIT); + } else { + updateZoom(ZOOM_FREE, d->mZoomBeforeAuto, d->mXCenterBeforeAuto, d->mYCenterBeforeAuto); + } +} + + +void ImageView::setZoomToWidth(bool on) { + if (on) { + updateZoom(ZOOM_FIT_WIDTH); + } else { + updateZoom(ZOOM_FREE, d->mZoomBeforeAuto, d->mXCenterBeforeAuto, d->mYCenterBeforeAuto); + } +} + + +void ImageView::setZoomToHeight(bool on) { + if (on) { + updateZoom(ZOOM_FIT_HEIGHT); + } else { + updateZoom(ZOOM_FREE, d->mZoomBeforeAuto, d->mXCenterBeforeAuto, d->mYCenterBeforeAuto); + } +} + + +void ImageView::setLockZoom(bool value) { + if( value ) { + d->mZoomToFit->setChecked( false ); + d->mZoomToWidth->setChecked( false ); + d->mZoomToHeight->setChecked( false ); + } + // don't change zoom here, keep it even if it was from some auto zoom mode +} + + +void ImageView::showBCGDialog() { + if (!d->mBCGDialog) { + d->mBCGDialog=new BCGDialog(this); + } + d->mBCGDialog->show(); +} + + +int ImageView::brightness() const { + return d->mBrightness; +} + + +void ImageView::setBrightness(int value) { + d->mBrightness=value; + fullRepaint(); +} + +void ImageView::increaseBrightness() { + d->mBrightness = KCLAMP( d->mBrightness + 5, -100, 100 ); + emit bcgChanged(); + fullRepaint(); +} + +void ImageView::decreaseBrightness() { + d->mBrightness = KCLAMP( d->mBrightness - 5, -100, 100 ); + emit bcgChanged(); + fullRepaint(); +} + + + +int ImageView::contrast() const { + return d->mContrast - 100; +} + +void ImageView::setContrast(int value) { + d->mContrast=value + 100; + fullRepaint(); +} + +void ImageView::increaseContrast() { + d->mContrast = KCLAMP( d->mContrast + 10, 0, 500 ); + emit bcgChanged(); + fullRepaint(); +} + +void ImageView::decreaseContrast() { + d->mContrast = KCLAMP( d->mContrast - 10, 0, 500 ); + emit bcgChanged(); + fullRepaint(); +} + + + +int ImageView::gamma() const { + return d->mGamma - 100; +} + + +void ImageView::setGamma(int value) { + d->mGamma=value + 100; + fullRepaint(); +} + +void ImageView::increaseGamma() { + d->mGamma = KCLAMP( d->mGamma + 10, 10, 500 ); + emit bcgChanged(); + fullRepaint(); +} + +void ImageView::decreaseGamma() { + d->mGamma = KCLAMP( d->mGamma - 10, 10, 500 ); + emit bcgChanged(); + fullRepaint(); +} +//------------------------------------------------------------------------ +// +// Private +// +//------------------------------------------------------------------------ +void ImageView::emitRequestHintDisplay() { + if (d->mDocument->isNull()) return; + + emit requestHintDisplay( d->mTools[d->mToolID]->hint() ); +} + + +void ImageView::slotImageSizeUpdated() { + d->mXOffset=0; + d->mYOffset=0; + + d->mValidImageArea = QRegion(); + if (d->mZoomMode!=ZOOM_FREE) { + d->mXCenterBeforeAuto=0; + d->mYCenterBeforeAuto=0; + } else { + horizontalScrollBar()->setValue(0); + verticalScrollBar()->setValue(0); + } + if (d->mZoomMode!=ZOOM_FREE) { + updateZoom(d->mZoomMode); + } else { + if( !d->mLockZoom->isChecked()) { + setZoom( 1.0 ); + } + } + + updateZoomActions(); + d->mAdjustBCG->setEnabled(!d->mDocument->isNull()); + d->mIncreaseGamma->setEnabled(!d->mDocument->isNull()); + d->mDecreaseGamma->setEnabled(!d->mDocument->isNull()); + d->mIncreaseBrightness->setEnabled(!d->mDocument->isNull()); + d->mDecreaseBrightness->setEnabled(!d->mDocument->isNull()); + d->mIncreaseContrast->setEnabled(!d->mDocument->isNull()); + d->mDecreaseContrast->setEnabled(!d->mDocument->isNull()); + + updateContentSize(); + updateImageOffset(); + updateScrollBarMode(); + fullRepaint(); +} + +void ImageView::slotImageRectUpdated(const QRect& imageRect) { + d->mValidImageArea += imageRect; + viewport()->repaint( d->imageToWidget( imageRect ), false ); +} + + +void ImageView::updateScrollBarMode() { + if (d->mZoomMode==ZOOM_FIT || !ImageViewConfig::showScrollBars()) { + setVScrollBarMode(AlwaysOff); + setHScrollBarMode(AlwaysOff); + } else { + setVScrollBarMode(Auto); + setHScrollBarMode(Auto); + } +} + + +void ImageView::updateContentSize() { + resizeContents( + int(d->mDocument->width()*d->mZoom), + int(d->mDocument->height()*d->mZoom) ); +} + +double ImageView::computeZoomToFit() const { + if (d->mDocument->isNull()) { + return 1.0; + } + QSize size=d->mDocument->image().size(); + size.scale(width(),height(),QSize::ScaleMin); + + double zoom=double(size.width())/d->mDocument->width(); + if (zoom>1.0 && !ImageViewConfig::enlargeSmallImages()) return 1.0; + return zoom; +} + +double ImageView::computeZoomToWidth() const { + if (d->mDocument->isNull()) { + return 1.0; + } + int sw = verticalScrollBar()->sizeHint().width(); // geometry is not valid before first show() + int w = width(); + int dw = d->mDocument->width(); + switch( vScrollBarMode()) { + case AlwaysOff: + return double(w)/dw; + case AlwaysOn: + return double(w-sw)/dw; + case Auto: + default: + // there will be a vertical scrollbar if the image's height will be too large + if( d->mDocument->height() * (double(w)/dw) > height()) return double(w-sw)/dw; + return double(w)/dw; + } +} + +double ImageView::computeZoomToHeight() const { + if (d->mDocument->isNull()) { + return 1.0; + } + int sh = horizontalScrollBar()->sizeHint().height(); + int h = height(); + int dh = d->mDocument->height(); + switch( vScrollBarMode()) { + case AlwaysOff: + return double(h)/dh; + case AlwaysOn: + return double(h-sh)/dh; + case Auto: + default: + if( d->mDocument->width() * (double(h)/dh) > width()) return double(h-sh)/dh; + return double(h)/dh; + } +} + +double ImageView::computeZoom(bool in) const { + const double F = 0.5; // change in 0.5 steps + double zoomtofit = computeZoomToFit(); + double zoomtowidth = computeZoomToWidth(); + double zoomtoheight = computeZoomToHeight(); + if (in) { + double newzoom; + if (d->mZoom>=1.0) { + newzoom = (floor(d->mZoom/F)+1.0)*F; + } else { + newzoom = 1/(( ceil(1/d->mZoom/F)-1.0 )*F); + } + if( d->mZoom < zoomtofit && zoomtofit < newzoom ) newzoom = zoomtofit; + if( d->mZoom < zoomtowidth && zoomtowidth < newzoom ) newzoom = zoomtowidth; + if( d->mZoom < zoomtoheight && zoomtoheight < newzoom ) newzoom = zoomtoheight; + return newzoom; + } else { + double newzoom; + if (d->mZoom>1.0) { + newzoom = (ceil(d->mZoom/F)-1.0)*F; + } else { + newzoom = 1/(( floor(1/d->mZoom/F)+1.0 )*F); + } + if( d->mZoom > zoomtofit && zoomtofit > newzoom ) newzoom = zoomtofit; + if( d->mZoom > zoomtowidth && zoomtowidth > newzoom ) newzoom = zoomtowidth; + if( d->mZoom > zoomtoheight && zoomtoheight > newzoom ) newzoom = zoomtoheight; + return newzoom; + } +} + +void ImageView::updateImageOffset() { + int viewWidth=width(); + int viewHeight=height(); + + // Compute d->mXOffset and d->mYOffset in case the image does not fit + // the view width or height + int zpixWidth=int(d->mDocument->width() * d->mZoom); + int zpixHeight=int(d->mDocument->height() * d->mZoom); + + if (zpixWidth>viewWidth && hScrollBarMode()!=AlwaysOff) { + // use sizeHint() - geometry is not valid before first show() + viewHeight-=horizontalScrollBar()->sizeHint().height(); + } + if (zpixHeight>viewHeight && vScrollBarMode()!=AlwaysOff) { + viewWidth-=verticalScrollBar()->sizeHint().width(); + } + + d->mXOffset=QMAX(0,(viewWidth-zpixWidth)/2); + d->mYOffset=QMAX(0,(viewHeight-zpixHeight)/2); +} + + +void ImageView::updateZoomActions() { + // Disable most actions if there's no image + if (d->mDocument->isNull()) { + d->mZoomComboAction->setEnabled(false); + d->mZoomIn->setEnabled(false); + d->mZoomOut->setEnabled(false); + d->mResetZoom->setEnabled(false); + return; + } + + d->mZoomComboAction->setEnabled(true); + d->mZoomToFit->setEnabled(true); + d->mZoomToWidth->setEnabled(true); + d->mZoomToHeight->setEnabled(true); + d->mResetZoom->setEnabled(true); + + + if (d->mZoomMode==ZOOM_FREE) { + d->mZoomIn->setEnabled(d->mZoommZoomOut->setEnabled(d->mZoom>1/MAX_ZOOM); + QString zoomText=QString("%1%").arg(int(d->mZoom*100)); + d->mZoomCombo->setCurrentText(zoomText); + } else { + d->mZoomIn->setEnabled(true); + d->mZoomOut->setEnabled(true); + d->mZoomCombo->setCurrentItem(d->mZoomMode); + } +} + +} // namespace diff --git a/src/gvcore/imageview.h b/src/gvcore/imageview.h new file mode 100644 index 0000000..74e3c66 --- /dev/null +++ b/src/gvcore/imageview.h @@ -0,0 +1,190 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + + +#ifndef IMAGEVIEW_H +#define IMAGEVIEW_H + +// Qt +#include +#include +#include +#include + +// Local +#include "busylevelmanager.h" +#include "imageutils/imageutils.h" +#include "libgwenview_export.h" +class QEvent; +class QLabel; +class QMouseEvent; +class QPainter; +class QTimer; +class QWheelEvent; +class KAction; +class KActionCollection; +class KToggleAction; +typedef QValueList KActionPtrList; + +namespace Gwenview { +class Document; + +class LIBGWENVIEW_EXPORT ImageView : public QScrollView { +Q_OBJECT + +public: + class ToolBase; + class ZoomTool; + class ScrollTool; + class EventFilter; +#if __GNUC__ < 3 + friend class ToolBase; + friend class ZoomTool; + friend class ScrollTool; +#endif + friend class EventFilter; + + enum ToolID { SCROLL, ZOOM }; + enum ZoomMode { ZOOM_FIT, ZOOM_FIT_WIDTH, ZOOM_FIT_HEIGHT, ZOOM_FREE }; + typedef QMap Tools; + + ImageView(QWidget* parent,Document*,KActionCollection*); + ~ImageView(); + + // Properties + double zoom() const; + void setZoom(double zoom, int centerX=-1, int centerY=-1); + bool fullScreen() const; + void setFullScreen(bool); + + int brightness() const; + int contrast() const; + int gamma() const; + +public slots: + void setBrightness(int); + void setContrast(int); + void setGamma(int); + void updateFromSettings(); + +signals: + void selectPrevious(); + void selectNext(); + void doubleClicked(); + void requestContextMenu(const QPoint&); + + // Emitted whenever an hint should be displayed + void requestHintDisplay(const QString& hint); + + // Emitted whenever brightness, contrast or gamma changes + void bcgChanged(); + +protected: + virtual void contentsDragEnterEvent(QDragEnterEvent*); + virtual void contentsDropEvent(QDropEvent*); + virtual void keyPressEvent(QKeyEvent*); + +private: + struct Private; + Private* d; + + struct PendingPaint { + PendingPaint( bool s, const QRect& r ) : rect( r ), smooth( s ) {}; + PendingPaint() {}; // stupid Qt containers + QRect rect; + bool smooth; + }; + enum Operation { CHECK_OPERATIONS = 0, SMOOTH_PASS = 1 << 0 }; + + void addPendingPaint( bool smooth, QRect rect = QRect()); + void addPendingPaintInternal( bool smooth, QRect rect = QRect()); + void performPaint( QPainter* painter, int clipx, int clipy, int clipw, int cliph, bool smooth ); + void limitPaintSize( PendingPaint& paint ); + void fullRepaint(); + void cancelPending(); + void scheduleOperation( Operation operation ); + void checkPendingOperationsInternal(); + void updateBusyLevels(); + + void updateZoom(ZoomMode, double value=0, int centerX=-1, int centerY=-1); + double computeZoom(bool in) const; + double computeZoomToFit() const; + double computeZoomToWidth() const; + double computeZoomToHeight() const; + + void updateImageOffset(); + void updateScrollBarMode(); + void updateContentSize(); + void updateFullScreenLabel(); + void updateZoomActions(); + void selectTool(ButtonState, bool force); + void restartAutoHideTimer(); + + void emitRequestHintDisplay(); + + // Used by the scroll tool + void emitSelectPrevious() { emit selectPrevious(); } + void emitSelectNext() { emit selectNext(); } + + // Used by the zoom tool + QPoint offset() const; + bool canZoom(bool in) const; + KToggleAction* zoomToFit() const; + +private slots: + void slotLoaded(); + void slotModified(); + void slotZoomIn(); + void slotZoomOut(); + void slotResetZoom(); + void slotSelectZoom(); + void setZoomToFit(bool); + void setZoomToWidth(bool); + void setZoomToHeight(bool); + void setLockZoom(bool); + void increaseGamma(); + void decreaseGamma(); + void increaseBrightness(); + void decreaseBrightness(); + void increaseContrast(); + void decreaseContrast(); + void slotImageSizeUpdated(); + void slotImageRectUpdated(const QRect&); + void checkPendingOperations(); + void loadingStarted(); + void slotBusyLevelChanged(BusyLevel); + void showBCGDialog(); + +protected: + // Overloaded methods + bool eventFilter(QObject*, QEvent*); + void viewportMousePressEvent(QMouseEvent*); + void viewportMouseMoveEvent(QMouseEvent*); + void viewportMouseReleaseEvent(QMouseEvent*); + bool viewportKeyEvent(QKeyEvent*); // This one is not inherited, it's called from the eventFilter + void wheelEvent(QWheelEvent* event); + void resizeEvent(QResizeEvent* event); + void drawContents(QPainter* p,int clipx,int clipy,int clipw,int cliph); +}; + +} // namespace +#endif + diff --git a/src/gvcore/imageviewconfig.kcfg b/src/gvcore/imageviewconfig.kcfg new file mode 100644 index 0000000..f13dfad --- /dev/null +++ b/src/gvcore/imageviewconfig.kcfg @@ -0,0 +1,54 @@ + + + + qapplication.h + qpalette.h + + + + + + + + + + None + + + false + + + QApplication::palette().active().dark() + + + false + + + true + + + false + + + + + + + + + FitWindow + + + false + + + 10000 + + + 10000 + + + 10000 + + + diff --git a/src/gvcore/imageviewconfig.kcfgc b/src/gvcore/imageviewconfig.kcfgc new file mode 100644 index 0000000..6336197 --- /dev/null +++ b/src/gvcore/imageviewconfig.kcfgc @@ -0,0 +1,7 @@ +File=imageviewconfig.kcfg +ClassName=ImageViewConfig +NameSpace=Gwenview +Singleton=true +Mutators=true +IncludeFiles=gvcore/libgwenview_export.h +Visibility=LIBGWENVIEW_EXPORT diff --git a/src/gvcore/imageviewcontroller.cpp b/src/gvcore/imageviewcontroller.cpp new file mode 100644 index 0000000..85a587a --- /dev/null +++ b/src/gvcore/imageviewcontroller.cpp @@ -0,0 +1,527 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2006 Aurélien Gâteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include + +// Qt +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include +#include +#include +#include +#include + +namespace Gwenview { + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + + +/** + * A KXMLGUIBuilder which only creates containers for toolbars. + */ +class XMLGUIBuilder : public KXMLGUIBuilder { +public: + XMLGUIBuilder(QWidget* parent) : KXMLGUIBuilder(parent) {} + + virtual QWidget* createContainer(QWidget *parent, int index, const QDomElement &element, int &id) { + if (element.tagName().lower() == "toolbar") { + return KXMLGUIBuilder::createContainer(parent, index, element, id); + } else { + return 0; + } + } +}; + + +const int AUTO_HIDE_TIMEOUT=4000; + + +//------------------------------------------------------------------------ +// +// ImageViewController::Private +// +//------------------------------------------------------------------------ +struct ImageViewController::Private { + ImageViewController* mImageViewController; + + Document* mDocument; + KActionCollection* mActionCollection; + QWidget* mContainer; + KToolBar* mToolBar; + KXMLGUIFactory* mFactory; + XMLGUIBuilder* mBuilder; + QWidgetStack* mStack; + + ImageView* mImageView; + KActionPtrList mImageViewActions; + + // Hide cursor stuff + QTimer* mAutoHideTimer; + bool mCursorHidden; + + KParts::ReadOnlyPart* mPlayerPart; + + // Fullscreen stuff + bool mFullScreen; + FullScreenBar* mFullScreenBar; + KActionPtrList mFullScreenCommonActions; + + + void setXMLGUIClient(KXMLGUIClient* client) { + QPtrList list=mFactory->clients(); + KXMLGUIClient* oldClient=list.getFirst(); + if (oldClient) { + mFactory->removeClient(oldClient); + // There should be at most one client, so the list should be empty + // now + Q_ASSERT(!mFactory->clients().getFirst()); + } + + // Unplug image view actions, if plugged + KActionPtrList::Iterator + it=mImageViewActions.begin(), + end=mImageViewActions.end(); + for (; it!=end; ++it) { + KAction* action=*it; + if (action->isPlugged(mToolBar)) { + action->unplug(mToolBar); + } + } + + if (client) { + mFactory->addClient(client); + } + } + + + void createPlayerPart(void) { + if (mPlayerPart) { + setXMLGUIClient(0); + delete mPlayerPart; + } + mPlayerPart=0; + + QString mimeType=KMimeType::findByURL(mDocument->url())->name(); + KService::Ptr service = KServiceTypeProfile::preferredService(mimeType, "KParts/ReadOnlyPart"); + if (!service) { + kdWarning() << "Couldn't find a KPart for " << mimeType << endl; + return; + } + + QString library=service->library(); + Q_ASSERT(!library.isNull()); + LOG("Library:" << library); + mPlayerPart = KParts::ComponentFactory::createPartInstanceFromService(service, mStack, 0, mStack, 0); + if (!mPlayerPart) { + kdWarning() << "Failed to instantiate KPart from library " << library << endl; + return; + } + mStack->addWidget(mPlayerPart->widget()); + setXMLGUIClient(mPlayerPart); + } + + + void showPlayerPart(void) { + LOG(""); + createPlayerPart(); + if (!mPlayerPart) return; + mStack->raiseWidget(mPlayerPart->widget()); + mPlayerPart->openURL(mDocument->url()); + + // If the part implements the KMediaPlayer::Player interface, start + // playing (needed for Kaboodle) + KMediaPlayer::Player* player=dynamic_cast(mPlayerPart); + if (player) { + player->play(); + } + } + + + void showImageView(void) { + LOG(""); + if (mStack->visibleWidget()==mImageView) { + KAction* action=mImageViewActions.first(); + if (action && !action->isPlugged(mToolBar)) { + // In the ctor, we set the imageview as the visible widget but + // we did not fill the toolbar because mImageViewActions was + // empty. In this case, fill the toolbar now. + plugImageViewActions(); + } + return; + } + + if (mPlayerPart) { + setXMLGUIClient(0); + delete mPlayerPart; + mPlayerPart=0; + } + plugImageViewActions(); + mStack->raiseWidget(mImageView); + } + + void plugImageViewActions() { + KActionPtrList::Iterator + it=mImageViewActions.begin(), + end=mImageViewActions.end(); + for (; it!=end; ++it) { + KAction* action=*it; + action->plug(mToolBar); + } + } + + + void restartAutoHideTimer() { + mAutoHideTimer->start(AUTO_HIDE_TIMEOUT,true); + } + + + void updateFullScreenBarPosition() { + int mouseY=mStack->mapFromGlobal(QCursor::pos()).y(); + bool visible = mFullScreenBar->y()==0; + + if (visible && mouseY>mFullScreenBar->height()) { + mFullScreenBar->slideOut(); + } + + if (!visible && mouseY<2) { + mFullScreenBar->slideIn(); + } + } + + + /** + * This function creates the fullscreen toolbar. + * NOTE: It should not be called from/merged with setFullScreenActions, + * otherwise the toolbar will have a one pixel border which will prevent + * reaching easily buttons by pushing the mouse to the top edge of the + * screen. + * My guess is that instanciating the toolbar *before* the main + * window is shown causes the main window to tweak its bars. This happens + * with KDE 3.5.1. + */ + void initFullScreenBar() { + Q_ASSERT(!mFullScreenBar); + mFullScreenBar=new FullScreenBar(mContainer); + + KActionPtrList::ConstIterator + it=mFullScreenCommonActions.begin(), + end=mFullScreenCommonActions.end(); + + for (; it!=end; ++it) { + (*it)->plug(mFullScreenBar); + } + } +}; + + +//------------------------------------------------------------------------ +// +// ImageViewController +// +//------------------------------------------------------------------------ + + +ImageViewController::ImageViewController(QWidget* parent, Document* document, KActionCollection* actionCollection) +: QObject(parent) { + d=new Private; + d->mImageViewController=this; + d->mDocument=document; + d->mActionCollection=actionCollection; + d->mAutoHideTimer=new QTimer(this); + d->mCursorHidden=false; + + d->mContainer=new QWidget(parent); + d->mContainer->setMinimumWidth(1); // Make sure we can resize the toolbar smaller than its minimum size + QVBoxLayout* layout=new QVBoxLayout(d->mContainer); + d->mToolBar=new KToolBar(d->mContainer, "", true); + + layout->add(d->mToolBar); + d->mStack=new QWidgetStack(d->mContainer); + layout->add(d->mStack); + + d->mImageView=new ImageView(d->mStack, document, actionCollection); + d->mStack->addWidget(d->mImageView); + + KApplication::kApplication()->installEventFilter(this); + + d->mPlayerPart=0; + d->mBuilder=new XMLGUIBuilder(d->mToolBar); + d->mFactory=new KXMLGUIFactory(d->mBuilder, this); + + d->mFullScreen=false; + d->mFullScreenBar=0; + + connect(d->mDocument,SIGNAL(loaded(const KURL&)), + this,SLOT(slotLoaded()) ); + + connect(d->mImageView, SIGNAL(requestContextMenu(const QPoint&)), + this, SLOT(openImageViewContextMenu(const QPoint&)) ); + + connect(d->mImageView, SIGNAL(requestHintDisplay(const QString&)), + this, SIGNAL(requestHintDisplay(const QString&)) ); + + connect(d->mAutoHideTimer,SIGNAL(timeout()), + this,SLOT(slotAutoHide()) ); + + // Forward Image view signals + connect(d->mImageView, SIGNAL(selectPrevious()), SIGNAL(selectPrevious()) ); + connect(d->mImageView, SIGNAL(selectNext()), SIGNAL(selectNext()) ); + connect(d->mImageView, SIGNAL(doubleClicked()), SIGNAL(doubleClicked()) ); +} + + +ImageViewController::~ImageViewController() { + delete d->mBuilder; + delete d; +} + + +void ImageViewController::setFocus() { + QWidget* view; + if (d->mPlayerPart) { + view = d->mPlayerPart->widget(); + } else { + view = d->mImageView; + } + view->setFocus(); +} + + +void ImageViewController::slotLoaded() { + LOG(""); + if (d->mDocument->urlKind()==MimeTypeUtils::KIND_FILE) { + d->showPlayerPart(); + } else { + d->showImageView(); + } +} + + +void ImageViewController::setFullScreen(bool fullScreen) { + d->mFullScreen=fullScreen; + d->mImageView->setFullScreen(fullScreen); + + if (d->mFullScreen) { + d->restartAutoHideTimer(); + if (!d->mFullScreenBar) { + d->initFullScreenBar(); + } + } else { + d->mAutoHideTimer->stop(); + QApplication::restoreOverrideCursor(); + d->mCursorHidden=false; + } + + d->mToolBar->setHidden(d->mFullScreen); + if (d->mFullScreenBar) { + d->mFullScreenBar->setHidden(!d->mFullScreen); + } +} + + +void ImageViewController::setNormalCommonActions(const KActionPtrList& actions) { + KActionPtrList::ConstIterator + it=actions.begin(), + end=actions.end(); + + for (; it!=end; ++it) { + (*it)->plug(d->mToolBar); + } + d->mToolBar->insertLineSeparator(); +} + + +void ImageViewController::setFullScreenCommonActions(const KActionPtrList& actions) { + d->mFullScreenCommonActions=actions; +} + + +void ImageViewController::setImageViewActions(const KActionPtrList& actions) { + d->mImageViewActions=actions; +} + + +void ImageViewController::slotAutoHide() { + if (d->mFullScreenBar) { + // Do not auto hide if the cursor is over the bar + QPoint pos=d->mFullScreenBar->mapFromGlobal(QCursor::pos()); + if (d->mFullScreenBar->rect().contains(pos)) { + d->restartAutoHideTimer(); + return; + } + } + + // Only hide cursor if we are not over a dialog + QWidget* widget = KApplication::kApplication()->activeWindow(); + if (!widget || !widget->inherits("QDialog")) { + QApplication::setOverrideCursor(blankCursor); + d->mCursorHidden=true; + } +} + + +QWidget* ImageViewController::widget() const { + return d->mContainer; +} + + +void ImageViewController::updateFromSettings() { + d->mImageView->updateFromSettings(); +} + + +/** + * This event filter monitors mouse moves and make sure the position of the + * fullscreen bar is updated. + */ +bool ImageViewController::eventFilter(QObject* object, QEvent* event) { + if (!d->mFullScreen) return false; + if (!event->type()==QEvent::MouseMove) return false; + + // Check we must filter this object. This is an application filter, so we + // have to check we are not dealing with another object. + bool isAChildOfStack=false; + QObject* parentObject; + for (parentObject=object->parent(); parentObject; parentObject=parentObject->parent()) { + if (parentObject==d->mStack) { + isAChildOfStack=true; + break; + } + } + if (!isAChildOfStack) return false; + + d->updateFullScreenBarPosition(); + + if (event->type()==QEvent::MouseMove) { + d->mCursorHidden=false; + d->restartAutoHideTimer(); + } + + if (d->mCursorHidden) { + QApplication::setOverrideCursor(blankCursor,true); + } else { + QApplication::restoreOverrideCursor(); + } + + return false; +} + + +/** + * Little helper to plug an action if it exists + */ +inline void plugAction(QPopupMenu* menu, KActionCollection* actionCollection, const char* actionName) { + KAction* action=actionCollection->action(actionName); + if (action) action->plug(menu); +} + + +void ImageViewController::openImageViewContextMenu(const QPoint& pos) { + QPopupMenu menu(d->mImageView); + bool noImage=d->mDocument->filename().isEmpty(); + bool validImage=!d->mDocument->isNull(); + + // The fullscreen item is always there, to be able to leave fullscreen mode + // if necessary. But KParts may not have the action itself. + plugAction(&menu, d->mActionCollection, "fullscreen"); + + plugAction(&menu, d->mActionCollection, "slideshow"); + + if (validImage) { + menu.insertSeparator(); + + plugAction(&menu, d->mActionCollection, "view_zoom_to_fit"); + plugAction(&menu, d->mActionCollection, "view_zoom_in"); + plugAction(&menu, d->mActionCollection, "view_zoom_out"); + plugAction(&menu, d->mActionCollection, "view_actual_size"); + plugAction(&menu, d->mActionCollection, "view_zoom_lock"); + } + + menu.insertSeparator(); + + plugAction(&menu, d->mActionCollection, "first"); + plugAction(&menu, d->mActionCollection, "previous"); + plugAction(&menu, d->mActionCollection, "next"); + plugAction(&menu, d->mActionCollection, "last"); + + if (validImage) { + menu.insertSeparator(); + + QPopupMenu* editMenu=new QPopupMenu(&menu); + plugAction(editMenu, d->mActionCollection, "rotate_left"); + plugAction(editMenu, d->mActionCollection, "rotate_right"); + plugAction(editMenu, d->mActionCollection, "mirror"); + plugAction(editMenu, d->mActionCollection, "flip"); + plugAction(editMenu, d->mActionCollection, "adjust_bcg"); + menu.insertItem( i18n("Edit"), editMenu ); + + ExternalToolContext* externalToolContext= + ExternalToolManager::instance()->createContext( + this, d->mDocument->url()); + + menu.insertItem( + i18n("External Tools"), externalToolContext->popupMenu()); + } + + if (!noImage) { + menu.insertSeparator(); + + plugAction(&menu, d->mActionCollection, "file_rename"); + plugAction(&menu, d->mActionCollection, "file_copy"); + plugAction(&menu, d->mActionCollection, "file_move"); + plugAction(&menu, d->mActionCollection, "file_link"); + plugAction(&menu, d->mActionCollection, "file_delete"); + + menu.insertSeparator(); + + plugAction(&menu, d->mActionCollection, "file_properties"); + } + + menu.exec(pos); +} + + +} // namespace diff --git a/src/gvcore/imageviewcontroller.h b/src/gvcore/imageviewcontroller.h new file mode 100644 index 0000000..7ccb3be --- /dev/null +++ b/src/gvcore/imageviewcontroller.h @@ -0,0 +1,84 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2006 Aurélien Gâteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef IMAGEVIEWCONTROLLER_H +#define IMAGEVIEWCONTROLLER_H + +// Qt +#include + +// KDE +#include + +// Local +#include "libgwenview_export.h" + +class QPoint; +class QWidget; + +class KToolBar; + +namespace Gwenview { + + +class Document; +class ImageView; + + +class LIBGWENVIEW_EXPORT ImageViewController : public QObject { +Q_OBJECT +public: + ImageViewController(QWidget* parent, Document*, KActionCollection*); + ~ImageViewController(); + + QWidget* widget() const; + + void setImageViewActions(const KActionPtrList&); + + void setFullScreen(bool); + void setNormalCommonActions(const KActionPtrList&); + void setFullScreenCommonActions(const KActionPtrList&); + void setFocus(); + +protected: + virtual bool eventFilter(QObject*, QEvent*); + +public slots: + void updateFromSettings(); + +signals: + void requestHintDisplay(const QString&); + void selectPrevious(); + void selectNext(); + void doubleClicked(); + +private slots: + void slotLoaded(); + void openImageViewContextMenu(const QPoint&); + void slotAutoHide(); + +private: + struct Private; + Private* d; +}; + +} // namespace + +#endif /* IMAGEVIEWCONTROLLER_H */ diff --git a/src/gvcore/imageviewtools.cpp b/src/gvcore/imageviewtools.cpp new file mode 100644 index 0000000..06a483b --- /dev/null +++ b/src/gvcore/imageviewtools.cpp @@ -0,0 +1,213 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Our header +#include "imageviewtools.h" + +// KDE +#include +#include +#include +#include + +// Local +#include "imageviewconfig.h" + +namespace Gwenview { + + +// Helper function +static QCursor loadCursor(const QString& name) { + QString path; + path=locate("data", QString("gwenview/cursors/%1.png").arg(name)); + return QCursor(QPixmap(path)); +} + + +//---------------------------------------------------------------------------- +// +// ImageView::ToolBase +// +//---------------------------------------------------------------------------- +ImageView::ToolBase::ToolBase(ImageView* view) +: mView(view) {} + + +ImageView::ToolBase::~ToolBase() {} + +void ImageView::ToolBase::mouseMoveEvent(QMouseEvent*) {} +void ImageView::ToolBase::leftButtonPressEvent(QMouseEvent*) {} +void ImageView::ToolBase::leftButtonReleaseEvent(QMouseEvent*) {} + +void ImageView::ToolBase::midButtonReleaseEvent(QMouseEvent*) { + mView->zoomToFit()->activate(); +} + +void ImageView::ToolBase::rightButtonPressEvent(QMouseEvent* event) { + emit mView->requestContextMenu(event->globalPos()); +} + +void ImageView::ToolBase::rightButtonReleaseEvent(QMouseEvent*) { +} + +void ImageView::ToolBase::wheelEvent(QWheelEvent* event) { + event->accept(); +} + +void ImageView::ToolBase::updateCursor() { + mView->viewport()->setCursor(ArrowCursor); +} + + +//---------------------------------------------------------------------------- +// +// ImageView::ZoomTool +// +//---------------------------------------------------------------------------- +ImageView::ZoomTool::ZoomTool(ImageView* view) +: ImageView::ToolBase(view) { + mZoomCursor=loadCursor("zoom"); +} + + +void ImageView::ZoomTool::zoomTo(const QPoint& pos, bool in) { + if (!mView->canZoom(in)) return; + + QPoint centerPos=QPoint(mView->visibleWidth(), mView->visibleHeight())/2; + // Compute image position + QPoint imgPos=mView->viewportToContents(pos) - mView->offset(); + double newZoom=mView->computeZoom(in); + + imgPos*=newZoom/mView->zoom(); + imgPos=imgPos-pos+centerPos; + mView->setZoom(newZoom, imgPos.x(), imgPos.y()); +} + + +void ImageView::ZoomTool::leftButtonReleaseEvent(QMouseEvent* event) { + zoomTo(event->pos(), true); +} + + +void ImageView::ZoomTool::wheelEvent(QWheelEvent* event) { + zoomTo(event->pos(), event->delta()>0); + event->accept(); +} + + +void ImageView::ZoomTool::rightButtonPressEvent(QMouseEvent*) { +} + + +void ImageView::ZoomTool::rightButtonReleaseEvent(QMouseEvent* event) { + zoomTo(event->pos(), false); +} + + +void ImageView::ZoomTool::updateCursor() { + mView->viewport()->setCursor(mZoomCursor); +} + + +QString ImageView::ZoomTool::hint() const { + return i18n("Left click to zoom in, right click to zoom out. You can also use the mouse wheel."); +} + + +//---------------------------------------------------------------------------- +// +// ImageView::ScrollTool +// +//---------------------------------------------------------------------------- +ImageView::ScrollTool::ScrollTool(ImageView* view) +: ImageView::ToolBase(view) +, mScrollStartX(0), mScrollStartY(0) +, mDragStarted(false) { +} + + +void ImageView::ScrollTool::leftButtonPressEvent(QMouseEvent* event) { + mScrollStartX=event->x(); + mScrollStartY=event->y(); + mView->viewport()->setCursor(SizeAllCursor); + mDragStarted=true; +} + + +void ImageView::ScrollTool::mouseMoveEvent(QMouseEvent* event) { + if (!mDragStarted) return; + + int deltaX,deltaY; + + deltaX=mScrollStartX - event->x(); + deltaY=mScrollStartY - event->y(); + + mScrollStartX=event->x(); + mScrollStartY=event->y(); + mView->scrollBy(deltaX,deltaY); +} + + +void ImageView::ScrollTool::leftButtonReleaseEvent(QMouseEvent*) { + if (!mDragStarted) return; + + mDragStarted=false; + mView->viewport()->setCursor(ArrowCursor); +} + + +void ImageView::ScrollTool::wheelEvent(QWheelEvent* event) { + if (ImageViewConfig::mouseWheelScroll()) { + int deltaX, deltaY; + + if (event->state() & AltButton || event->orientation()==Horizontal) { + deltaX = event->delta(); + deltaY = 0; + } else { + deltaX = 0; + deltaY = event->delta(); + } + mView->scrollBy(-deltaX, -deltaY); + } else { + if (event->delta()<0) { + mView->emitSelectNext(); + } else { + mView->emitSelectPrevious(); + } + } + event->accept(); +} + + +void ImageView::ScrollTool::updateCursor() { + if (mDragStarted) { + mView->viewport()->setCursor(SizeAllCursor); + } else { + mView->viewport()->setCursor(ArrowCursor); + } +} + + +QString ImageView::ScrollTool::hint() const { + return i18n("Drag to move the image, middle-click to toggle auto-zoom. Hold the Control key to switch to the zoom tool."); +} + + +} // namespace diff --git a/src/gvcore/imageviewtools.h b/src/gvcore/imageviewtools.h new file mode 100644 index 0000000..59ce3e2 --- /dev/null +++ b/src/gvcore/imageviewtools.h @@ -0,0 +1,96 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef IMAGEVIEWTOOLS_H +#define IMAGEVIEWTOOLS_H + +// Qt +#include + +// Local +#include "imageview.h" +namespace Gwenview { + + +class ImageView::ToolBase { +protected: + ImageView* mView; + +public: + ToolBase(ImageView* view); + virtual ~ToolBase(); + virtual void mouseMoveEvent(QMouseEvent*); + + virtual void leftButtonPressEvent(QMouseEvent*); + virtual void leftButtonReleaseEvent(QMouseEvent*); + + virtual void midButtonReleaseEvent(QMouseEvent*); + + virtual void rightButtonPressEvent(QMouseEvent* event); + virtual void rightButtonReleaseEvent(QMouseEvent*); + + virtual void wheelEvent(QWheelEvent* event); + + virtual void updateCursor(); + + /** + * Return a hint about the use of the tool + */ + virtual QString hint() const=0; +}; + + +class ImageView::ZoomTool : public ImageView::ToolBase { +private: + QCursor mZoomCursor; + void zoomTo(const QPoint& pos, bool in); + +public: + ZoomTool(ImageView* view); + void leftButtonReleaseEvent(QMouseEvent* event); + + void wheelEvent(QWheelEvent* event); + void rightButtonPressEvent(QMouseEvent*); + void rightButtonReleaseEvent(QMouseEvent* event); + + void updateCursor(); + virtual QString hint() const; +}; + + +class ImageView::ScrollTool : public ImageView::ToolBase { + int mScrollStartX,mScrollStartY; + bool mDragStarted; + +public: + ScrollTool(ImageView* view); + void leftButtonPressEvent(QMouseEvent* event); + void mouseMoveEvent(QMouseEvent* event); + void leftButtonReleaseEvent(QMouseEvent*); + void wheelEvent(QWheelEvent* event); + + void updateCursor(); + virtual QString hint() const; +}; + + +} // namespace +#endif /* IMAGEVIEWTOOLS_H */ + diff --git a/src/gvcore/inputdialog.cpp b/src/gvcore/inputdialog.cpp new file mode 100644 index 0000000..3da70e9 --- /dev/null +++ b/src/gvcore/inputdialog.cpp @@ -0,0 +1,78 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2006 Aurélien Gâteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Self +#include "inputdialog.moc" + +// Qt +#include +#include + +// KDE +#include + +namespace Gwenview { + +struct InputDialog::Private { + KLineEdit* mLineEdit; + QLabel* mLabel; +}; + + +InputDialog::InputDialog(QWidget* parent) +: KDialogBase(parent, "InputDialog", true, QString::null, + KDialogBase::Ok|KDialogBase::Cancel) +{ + d = new Private; + QVBox* page = makeVBoxMainWidget(); + d->mLabel = new QLabel(page); + + d->mLineEdit = new KLineEdit(page); + d->mLineEdit->setFocus(); + + setMinimumWidth(350); + + connect(d->mLineEdit, SIGNAL(textChanged(const QString&)), + this, SLOT(updateButtons()) ); +} + + +InputDialog::~InputDialog() { + delete d; +} + + +void InputDialog::setLabel(const QString& label) { + d->mLabel->setText(label); +} + + +KLineEdit* InputDialog::lineEdit() const { + return d->mLineEdit; +} + + +void InputDialog::updateButtons() { + enableButtonOK( ! d->mLineEdit->text().isEmpty() ); +} + + +} // namespace + diff --git a/src/gvcore/inputdialog.h b/src/gvcore/inputdialog.h new file mode 100644 index 0000000..a849eb5 --- /dev/null +++ b/src/gvcore/inputdialog.h @@ -0,0 +1,55 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2006 Aurélien Gâteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef INPUTDIALOG_H +#define INPUTDIALOG_H + +// KDE +#include + + +class KLineEdit; + + +namespace Gwenview { + + +/** + * An input dialog which give access to its line edit + */ +class InputDialog : public KDialogBase { +Q_OBJECT +public: + InputDialog(QWidget* parent); + ~InputDialog(); + void setLabel(const QString& label); + KLineEdit* lineEdit() const; + +private slots: + void updateButtons(); + +private: + struct Private; + Private* d; +}; + +} // namespace + +#endif /* INPUTDIALOG_H */ diff --git a/src/gvcore/jpegformattype.cpp b/src/gvcore/jpegformattype.cpp new file mode 100644 index 0000000..ccb020e --- /dev/null +++ b/src/gvcore/jpegformattype.cpp @@ -0,0 +1,527 @@ +/* This file is based on kdelibs-3.2.0/khtml/misc/loader_jpeg.cpp. Original + * copyright follows. + */ +/* + This file is part of the KDE libraries + + Copyright (C) 2000 Dirk Mueller (mueller@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, sublicense, 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. + +*/ + + +// System +#include +#include +extern "C" { +#define XMD_H +#include +#undef const +} + +// Qt +#include + +// KDE +#include +#include + +// Local +#include "jpegformattype.h" +#include "imageutils/jpegerrormanager.h" + +namespace Gwenview { + +#undef BUFFER_DEBUG +//#define BUFFER_DEBUG + +#undef JPEG_DEBUG +//#define JPEG_DEBUG + + +static const int MAX_BUFFER = 32768; +// how long it will consume data before starting outputing progressive scan +static const int MAX_CONSUMING_TIME = 100; + +//----------------------------------------------------------------------------- +// +// JPEGSourceManager +// (Does not follow HACKING file recommandation to be consistent with +// jpeg_source_mgr naming) +// +//----------------------------------------------------------------------------- +struct JPEGSourceManager : public jpeg_source_mgr { + JOCTET jpeg_buffer[MAX_BUFFER]; + + int valid_buffer_length; + size_t skip_input_bytes; + bool at_eof; + QRect change_rect; + QRect old_change_rect; + QTime decoder_timestamp; + bool final_pass; + bool decoding_done; + bool do_progressive; + + JPEGSourceManager() { + // jpeg_source_mgr fields + init_source = gvJPEGDummyDecompress; + fill_input_buffer = gvFillInputBuffer; + skip_input_data = gvSkipInputData; + resync_to_restart = jpeg_resync_to_restart; + term_source = gvJPEGDummyDecompress; + + bytes_in_buffer = 0; + next_input_byte = jpeg_buffer; + + // JPEGSourceManager fields + valid_buffer_length = 0; + skip_input_bytes = 0; + at_eof = 0; + final_pass = false; + decoding_done = false; + } + + static void gvJPEGDummyDecompress(j_decompress_ptr) {} + + /* Do not replace boolean with bool, it's the libjpeg boolean type */ + static boolean gvFillInputBuffer(j_decompress_ptr cinfo) { +#ifdef BUFFER_DEBUG + qDebug("FillInputBuffer called!"); +#endif + + JPEGSourceManager* src = (JPEGSourceManager*)cinfo->src; + + if ( src->at_eof ) { + /* Insert a fake EOI marker - as per jpeglib recommendation */ + src->jpeg_buffer[0] = (JOCTET) 0xFF; + src->jpeg_buffer[1] = (JOCTET) JPEG_EOI; + src->bytes_in_buffer = 2; + src->next_input_byte = (JOCTET *) src->jpeg_buffer; +#ifdef BUFFER_DEBUG + qDebug("...returning true!"); +#endif + return true; + } else { + return false; /* I/O suspension mode */ + } + } + + static void gvSkipInputData(j_decompress_ptr cinfo, long num_bytes) { + if(num_bytes <= 0) return; /* required noop */ + +#ifdef BUFFER_DEBUG + qDebug("SkipInputData (%d) called!", num_bytes); +#endif + + JPEGSourceManager* src = (JPEGSourceManager*)cinfo->src; + src->skip_input_bytes += num_bytes; + + unsigned int skipbytes = kMin(src->bytes_in_buffer, src->skip_input_bytes); + +#ifdef BUFFER_DEBUG + qDebug("skip_input_bytes is now %d", src->skip_input_bytes); + qDebug("skipbytes is now %d", skipbytes); + qDebug("valid_buffer_length is before %d", src->valid_buffer_length); + qDebug("bytes_in_buffer is %d", src->bytes_in_buffer); +#endif + + if(skipbytes < src->bytes_in_buffer) { + memmove(src->jpeg_buffer, + src->next_input_byte+skipbytes, + src->bytes_in_buffer - skipbytes); + } + + src->bytes_in_buffer -= skipbytes; + src->valid_buffer_length = src->bytes_in_buffer; + src->skip_input_bytes -= skipbytes; + + /* adjust data for jpeglib */ + cinfo->src->next_input_byte = (JOCTET *) src->jpeg_buffer; + cinfo->src->bytes_in_buffer = (size_t) src->valid_buffer_length; +#ifdef BUFFER_DEBUG + qDebug("valid_buffer_length is afterwards %d", src->valid_buffer_length); + qDebug("skip_input_bytes is now %d", src->skip_input_bytes); +#endif + + } +}; + + +//----------------------------------------------------------------------------- +// +// JPEGFormat +// +//----------------------------------------------------------------------------- +class JPEGFormat : public QImageFormat { +public: + JPEGFormat(); + + virtual ~JPEGFormat(); + + virtual int decode(QImage& img, QImageConsumer* consumer, + const uchar* buffer, int length); +private: + + enum { + INIT, + START_DECOMPRESS, + DECOMPRESS_STARTED, + CONSUME_INPUT, + PREPARE_OUTPUT_SCAN, + DO_OUTPUT_SCAN, + READ_DONE, + INVALID + } mState; + + // structs for the jpeglib + jpeg_decompress_struct mDecompress; + ImageUtils::JPEGErrorManager mErrorManager; + JPEGSourceManager mSourceManager; +}; + + +JPEGFormat::JPEGFormat() { + memset(&mDecompress, 0, sizeof(mDecompress)); + mDecompress.err = &mErrorManager; + jpeg_create_decompress(&mDecompress); + mDecompress.src = &mSourceManager; + mState = INIT; +} + + +JPEGFormat::~JPEGFormat() { + (void) jpeg_destroy_decompress(&mDecompress); +} + +/* + * return > 0 means "consumed x bytes, need more" + * return == 0 means "end of frame reached" + * return < 0 means "fatal error in image decoding, don't call me ever again" + */ + +int JPEGFormat::decode(QImage& image, QImageConsumer* consumer, const uchar* buffer, int length) { +#ifdef JPEG_DEBUG + qDebug("JPEGFormat::decode(%p, %p, %p, %d)", + &image, consumer, buffer, length); +#endif + + if(mSourceManager.at_eof) { +#ifdef JPEG_DEBUG + qDebug("at_eof, eating"); +#endif + return length; + } + + if(setjmp(mErrorManager.jmp_buffer)) { +#ifdef JPEG_DEBUG + qDebug("jump into state INVALID"); +#endif + if(consumer) consumer->end(); + + // this is fatal + return -1; + } + + int consumed = kMin(length, MAX_BUFFER - mSourceManager.valid_buffer_length); + +#ifdef BUFFER_DEBUG + qDebug("consuming %d bytes", consumed); +#endif + + // filling buffer with the new data + memcpy(mSourceManager.jpeg_buffer + mSourceManager.valid_buffer_length, buffer, consumed); + mSourceManager.valid_buffer_length += consumed; + + if(mSourceManager.skip_input_bytes) { +#ifdef BUFFER_DEBUG + qDebug("doing skipping"); + qDebug("valid_buffer_length %d", mSourceManager.valid_buffer_length); + qDebug("skip_input_bytes %d", mSourceManager.skip_input_bytes); +#endif + int skipbytes = kMin((size_t) mSourceManager.valid_buffer_length, mSourceManager.skip_input_bytes); + + if(skipbytes < mSourceManager.valid_buffer_length) { + memmove(mSourceManager.jpeg_buffer, + mSourceManager.jpeg_buffer+skipbytes, + mSourceManager.valid_buffer_length - skipbytes); + } + + mSourceManager.valid_buffer_length -= skipbytes; + mSourceManager.skip_input_bytes -= skipbytes; + + // still more bytes to skip + if(mSourceManager.skip_input_bytes) { + if(consumed <= 0) qDebug("ERROR!!!"); + return consumed; + } + + } + + mDecompress.src->next_input_byte = (JOCTET *) mSourceManager.jpeg_buffer; + mDecompress.src->bytes_in_buffer = (size_t) mSourceManager.valid_buffer_length; + +#ifdef BUFFER_DEBUG + qDebug("buffer contains %d bytes", mSourceManager.valid_buffer_length); +#endif + + if(mState == INIT) { + if(jpeg_read_header(&mDecompress, true) != JPEG_SUSPENDED) { + if (consumer) { + consumer->setSize( + mDecompress.image_width/mDecompress.scale_denom, + mDecompress.image_height/mDecompress.scale_denom); + } + + mState = START_DECOMPRESS; + } + } + + if(mState == START_DECOMPRESS) { + mSourceManager.do_progressive = jpeg_has_multiple_scans( &mDecompress ); + +#ifdef JPEG_DEBUG + qDebug( "**** DOPROGRESSIVE: %d", mSourceManager.do_progressive ); +#endif + mDecompress.buffered_image = mSourceManager.do_progressive; + + // setup image sizes + jpeg_calc_output_dimensions( &mDecompress ); + + if (mDecompress.jpeg_color_space == JCS_YCbCr) { + mDecompress.out_color_space = JCS_RGB; + } + + mDecompress.do_fancy_upsampling = true; + mDecompress.do_block_smoothing = false; + mDecompress.quantize_colors = false; + + // false: IO suspension + if(jpeg_start_decompress(&mDecompress)) { + if ( mDecompress.output_components == 3 || mDecompress.output_components == 4) { + image.create( mDecompress.output_width, mDecompress.output_height, 32 ); + } else if ( mDecompress.output_components == 1 ) { + image.create( mDecompress.output_width, mDecompress.output_height, 8, 256 ); + for (int i=0; i<256; i++) { + image.setColor(i, qRgb(i,i,i)); + } + } + +#ifdef JPEG_DEBUG + qDebug("will create a picture %d/%d in size", mDecompress.output_width, mDecompress.output_height); +#endif + +#ifdef JPEG_DEBUG + qDebug("ok, going to DECOMPRESS_STARTED"); +#endif + + mSourceManager.decoder_timestamp.start(); + mState = mSourceManager.do_progressive ? DECOMPRESS_STARTED : DO_OUTPUT_SCAN; + } + } + +again: + + if(mState == DECOMPRESS_STARTED) { + mState = (!mSourceManager.final_pass && mSourceManager.decoder_timestamp.elapsed() < MAX_CONSUMING_TIME) + ? CONSUME_INPUT : PREPARE_OUTPUT_SCAN; + } + + if(mState == CONSUME_INPUT) { + int retval; + + do { + retval = jpeg_consume_input(&mDecompress); + } while (retval != JPEG_SUSPENDED && retval != JPEG_REACHED_EOI + && (retval != JPEG_REACHED_SOS || mSourceManager.decoder_timestamp.elapsed() < MAX_CONSUMING_TIME)); + + if( mSourceManager.final_pass + || mSourceManager.decoder_timestamp.elapsed() >= MAX_CONSUMING_TIME + || retval == JPEG_REACHED_EOI + || retval == JPEG_REACHED_SOS) { + mState = PREPARE_OUTPUT_SCAN; + } + } + + if(mState == PREPARE_OUTPUT_SCAN) { + if ( jpeg_start_output(&mDecompress, mDecompress.input_scan_number) ) { + mState = DO_OUTPUT_SCAN; + } + } + + if(mState == DO_OUTPUT_SCAN) { + if(image.isNull() || mSourceManager.decoding_done) { +#ifdef JPEG_DEBUG + qDebug("complete in doOutputscan, eating.."); +#endif + return consumed; + } + uchar** lines = image.jumpTable(); + int oldoutput_scanline = mDecompress.output_scanline; + + while(mDecompress.output_scanline < mDecompress.output_height && + jpeg_read_scanlines(&mDecompress, lines+mDecompress.output_scanline, mDecompress.output_height)) + ; // here happens all the magic of decoding + + int completed_scanlines = mDecompress.output_scanline - oldoutput_scanline; +#ifdef JPEG_DEBUG + qDebug("completed now %d scanlines", completed_scanlines); +#endif + + if ( mDecompress.output_components == 3 ) { + // Expand 24->32 bpp. + for (int j=oldoutput_scanline; j= MAX_CONSUMING_TIME ) { + if( !mSourceManager.old_change_rect.isEmpty()) { + consumer->changed(mSourceManager.old_change_rect); + mSourceManager.old_change_rect = QRect(); + } + consumer->changed(mSourceManager.change_rect); + mSourceManager.change_rect = QRect(); + mSourceManager.decoder_timestamp.restart(); + } + } + + if(mDecompress.output_scanline >= mDecompress.output_height) { + if ( mSourceManager.do_progressive ) { + jpeg_finish_output(&mDecompress); + mSourceManager.final_pass = jpeg_input_complete(&mDecompress); + mSourceManager.decoding_done = mSourceManager.final_pass && mDecompress.input_scan_number == mDecompress.output_scan_number; + if ( !mSourceManager.decoding_done ) { + mSourceManager.old_change_rect |= mSourceManager.change_rect; + mSourceManager.change_rect = QRect(); + } + } else { + mSourceManager.decoding_done = true; + } +#ifdef JPEG_DEBUG + qDebug("one pass is completed, final_pass = %d, dec_done: %d, complete: %d", + mSourceManager.final_pass, mSourceManager.decoding_done, jpeg_input_complete(&mDecompress)); +#endif + if(!mSourceManager.decoding_done) { +#ifdef JPEG_DEBUG + qDebug("starting another one, input_scan_number is %d/%d", mDecompress.input_scan_number, + mDecompress.output_scan_number); +#endif + mSourceManager.decoder_timestamp.restart(); + mState = DECOMPRESS_STARTED; + // don't return until necessary! + goto again; + } + } + + if(mState == DO_OUTPUT_SCAN && mSourceManager.decoding_done) { +#ifdef JPEG_DEBUG + qDebug("input is complete, cleaning up, returning.."); +#endif + if ( consumer && !mSourceManager.change_rect.isEmpty() ) { + consumer->changed( mSourceManager.change_rect ); + } + + if(consumer) consumer->end(); + + // get the density X and Y info and the related units to have + // the aspect ratio of the image + // field: units -- one byte: Units for the X and Y densities + // 0 => no units, X and Y specify the pixel aspect ratio + // 1 => X and Y are dots per inch + // 2 => X and Y are dots per cm + // Xdensity -- two bytes + // Ydensity -- two bytes + const float INCHESPERMETER = (100. / 2.54); + switch (mDecompress.density_unit) + { + case 0: // no units + break; + case 1: // dots per inch + image.setDotsPerMeterX(int(mDecompress.X_density * INCHESPERMETER)); + image.setDotsPerMeterY(int(mDecompress.Y_density * INCHESPERMETER)); + break; + case 2: // dots per cm + image.setDotsPerMeterX(mDecompress.X_density * 100); + image.setDotsPerMeterY(mDecompress.Y_density * 100); + break; + } + + mSourceManager.at_eof = true; + + (void) jpeg_finish_decompress(&mDecompress); + (void) jpeg_destroy_decompress(&mDecompress); + + mState = READ_DONE; + + return 0; + } + } + +#ifdef BUFFER_DEBUG + qDebug("valid_buffer_length is now %d", mSourceManager.valid_buffer_length); + qDebug("bytes_in_buffer is now %d", mSourceManager.bytes_in_buffer); + qDebug("consumed %d bytes", consumed); +#endif + if(mSourceManager.bytes_in_buffer + && mSourceManager.jpeg_buffer != mSourceManager.next_input_byte) { + memmove(mSourceManager.jpeg_buffer, + mSourceManager.next_input_byte, + mSourceManager.bytes_in_buffer); + } + mSourceManager.valid_buffer_length = mSourceManager.bytes_in_buffer; + return consumed; +} + + +//----------------------------------------------------------------------------- +// +// JPEGFormatType +// +//----------------------------------------------------------------------------- +QImageFormat* JPEGFormatType::decoderFor(const uchar* buffer, int length) { + if(length < 3) return 0; + + if(buffer[0] == 0377 && + buffer[1] == 0330 && + buffer[2] == 0377) { + return new JPEGFormat; + } + + return 0; +} + +const char* JPEGFormatType::formatName() const { + return "JPEG"; +} + +} // namespace diff --git a/src/gvcore/jpegformattype.h b/src/gvcore/jpegformattype.h new file mode 100644 index 0000000..b92b69d --- /dev/null +++ b/src/gvcore/jpegformattype.h @@ -0,0 +1,51 @@ +/* This file is based on kdelibs-3.2.0/khtml/misc/loader_jpeg.h. Original + * copyright follows. + */ +/* + This file is part of the KDE libraries + + Copyright (C) 2000 Dirk Mueller (mueller@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, sublicense, 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. + + This is a helper for progressive loading of JPEG's. +*/ + +#ifndef gvjpegformattype_h +#define gvjpegformattype_h + +#include + +namespace Gwenview { + +/** + * @internal + * + * An incremental loader factory for JPEG's. + */ +class JPEGFormatType : public QImageFormatType { +public: + QImageFormat* decoderFor(const uchar* buffer, int length); + const char* formatName() const; +}; + + +// ----------------------------------------------------------------------------- + +} // namespace +#endif // gvjpegformattype_h diff --git a/src/gvcore/libgwenview_export.h b/src/gvcore/libgwenview_export.h new file mode 100644 index 0000000..769141f --- /dev/null +++ b/src/gvcore/libgwenview_export.h @@ -0,0 +1,36 @@ +/* + This file is part of gwenview project + Copyright (c) 2005 Laurent Montel + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef _LIBGWENVIEW_EXPORT_H +#define _LIBGWENVIEW_EXPORT_H + +#include + +#ifdef __KDE_HAVE_GCC_VISIBILITY + +#define LIBGWENVIEW_EXPORT KDE_EXPORT + +#else +#define LIBGWENVIEW_EXPORT +#endif + +#endif /* _LIBGWENVIEW_EXPORT_H */ + + diff --git a/src/gvcore/mimetypeutils.cpp b/src/gvcore/mimetypeutils.cpp new file mode 100644 index 0000000..954a24b --- /dev/null +++ b/src/gvcore/mimetypeutils.cpp @@ -0,0 +1,87 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2006 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "mimetypeutils.h" + +// Qt +#include + +// KDE +#include +#include +#include +#include +#include +#include + +// Local +#include "archive.h" + + +namespace Gwenview { + +namespace MimeTypeUtils { + +const QStringList& rasterImageMimeTypes() { + static QStringList list; + if (list.isEmpty()) { + list=KImageIO::mimeTypes(KImageIO::Reading); + list.append("image/x-xcf-gimp"); + list.append("image/x-xcursor"); + // KImageIO does not return this one :'( + list.append("image/pjpeg"); + } + return list; +} + + +Kind mimeTypeKind(const QString& mimeType) { + if (mimeType.startsWith("inode/directory")) { + return KIND_DIR; + } + if (Archive::mimeTypes().contains(mimeType)) { + return KIND_ARCHIVE; + } + if (rasterImageMimeTypes().contains(mimeType)) { + return KIND_RASTER_IMAGE; + } + + return KIND_FILE; +} + + +Kind fileItemKind(const KFileItem* item) { + return mimeTypeKind(item->mimetype()); +} + + +Kind urlKind(const KURL& url) { + QString mimeType; + if (url.isLocalFile()) { + mimeType=KMimeType::findByURL(url)->name(); + } else { + mimeType=KIO::NetAccess::mimetype(url, KApplication::kApplication()->mainWidget()); + } + return mimeTypeKind(mimeType); +} + + +} // namespace MimeTypeUtils +} // namespace Gwenview diff --git a/src/gvcore/mimetypeutils.h b/src/gvcore/mimetypeutils.h new file mode 100644 index 0000000..02aa6dc --- /dev/null +++ b/src/gvcore/mimetypeutils.h @@ -0,0 +1,47 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2006 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef MIMETYPEUTILS_H +#define MIMETYPEUTILS_H + +// Local +#include "libgwenview_export.h" + +class KFileItem; +class KURL; + +class QString; +class QStringList; + +namespace Gwenview { + +namespace MimeTypeUtils { +enum Kind { KIND_UNKNOWN, KIND_DIR, KIND_ARCHIVE, KIND_FILE, KIND_RASTER_IMAGE }; + +LIBGWENVIEW_EXPORT const QStringList& rasterImageMimeTypes(); +Kind fileItemKind(const KFileItem*); +Kind urlKind(const KURL&); +Kind mimeTypeKind(const QString& mimeType); + +} // namespace FileUtils + +} // namespace Gwenview + +#endif /* MIMETYPEUTILS_H */ diff --git a/src/gvcore/miscconfig.kcfg b/src/gvcore/miscconfig.kcfg new file mode 100644 index 0000000..c3cc726 --- /dev/null +++ b/src/gvcore/miscconfig.kcfg @@ -0,0 +1,31 @@ + + + + + + + + true + + + + + + false + + + + false + + + + + + + + + + + + + diff --git a/src/gvcore/miscconfig.kcfgc b/src/gvcore/miscconfig.kcfgc new file mode 100644 index 0000000..3123823 --- /dev/null +++ b/src/gvcore/miscconfig.kcfgc @@ -0,0 +1,7 @@ +File=miscconfig.kcfg +ClassName=MiscConfig +NameSpace=Gwenview +Singleton=true +Mutators=true +IncludeFiles=gvcore/libgwenview_export.h +Visibility=LIBGWENVIEW_EXPORT diff --git a/src/gvcore/mngformattype.cpp b/src/gvcore/mngformattype.cpp new file mode 100644 index 0000000..60f64ef --- /dev/null +++ b/src/gvcore/mngformattype.cpp @@ -0,0 +1,520 @@ +// this code is copied from Qt, with fixes for not finishing decoding +// prematurely + +/* The actual patch is: +===== +--- /opt/_q/src/kernel/qmngio.cpp 2004-05-04 18:28:15.000000000 +0200 ++++ gvmngformattype.cpp 2005-04-13 16:11:50.000000000 +0200 +@@ -411,8 +417,11 @@ int QMNGFormat::decode( QImage& img, QIm + } + + losttime += losingtimer.elapsed(); +- if ( ndata || !length ) +- mng_display_resume(handle); ++ bool needmore = false; ++ if ( ndata ) { ++ mng_retcode r = mng_display_resume(handle); ++ needmore = ( r == MNG_NEEDMOREDATA ); ++ } + losingtimer.start(); + + image = 0; +@@ -422,6 +431,13 @@ int QMNGFormat::decode( QImage& img, QIm + // Move back unused tail + memcpy(buffer,buffer+ubuffer,nbuffer); + } ++ // "The function should return without processing all the data if it reaches the end of a frame in the input." ++ if( ndata && !needmore ) { ++ length -= ndata; ++ ndata = 0; ++ if( length == 0 ) // 0 means done, process at least one byte ++ length = ndata = 1; ++ } + if ( ndata ) { + // Not all used. + enlargeBuffer(nbuffer+ndata); +===== +*/ + +/**************************************************************************** +** +** +** Implementation of MNG QImage IOHandler +** +** Created : 970521 +** +** Copyright (C) 1997-2004 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 + +#ifndef QT_CLEAN_NAMESPACE +#define QT_CLEAN_NAMESPACE +#endif + +#include "qdatetime.h" +#include "mngformattype.h" + +//#ifndef QT_NO_IMAGEIO_MNG +#ifdef HAVE_LIBMNG + +#include "qimage.h" +#include "qasyncimageio.h" +#include "qiodevice.h" + +// Define XMD_H prohibits the included headers of libmng.h to typedef INT32. +// This is needed for Borland with STL support, since in that case, INT32 is +// already defined by some Borland header. +#define XMD_H +#if defined(Q_OS_UNIXWARE) +# define HAVE_BOOLEAN // libjpeg under Unixware seems to need this +#endif +#include +#include + + +#ifndef QT_NO_ASYNC_IMAGE_IO +namespace Gwenview { + +class MNGFormat : public QImageFormat { +public: + MNGFormat(); + virtual ~MNGFormat(); + + int decode(QImage& img, QImageConsumer* consumer, + const uchar* buffer, int length); + + bool openstream() + { + // ### We should figure out how many loops an MNG has, but for now always assume infinite. + if (consumer) + consumer->setLooping(0); + return TRUE; + } + bool closestream( ) + { + if (consumer) + consumer->end(); + return TRUE; + } + bool readdata( mng_ptr pBuf, mng_uint32 iBuflen, mng_uint32p pRead ) + { + uint m = ndata + nbuffer - ubuffer; + if ( iBuflen > m ) { + iBuflen = m; + } + *pRead = iBuflen; + uint n = nbuffer-ubuffer; + if ( iBuflen < n ) { + // enough in buffer + memcpy(pBuf, buffer+ubuffer, iBuflen); + ubuffer += iBuflen; + return TRUE; + } + if ( n ) { + // consume buffer + memcpy(pBuf, buffer+ubuffer, n ); + pBuf = (mng_ptr)((char*)pBuf + n); + iBuflen -= n; + ubuffer = nbuffer; + } + if ( iBuflen ) { + // fill from incoming data + memcpy(pBuf, data, iBuflen); + data += iBuflen; + ndata -= iBuflen; + } + return TRUE; + } + bool errorproc( mng_int32 iErrorcode, + mng_int8 /*iSeverity*/, + mng_chunkid iChunkname, + mng_uint32 /*iChunkseq*/, + mng_int32 iExtra1, + mng_int32 iExtra2, + mng_pchar zErrortext ) + { + qWarning("MNG error %d: %s; chunk %c%c%c%c; subcode %d:%d", + iErrorcode,zErrortext, + (iChunkname>>24)&0xff, + (iChunkname>>16)&0xff, + (iChunkname>>8)&0xff, + (iChunkname>>0)&0xff, + iExtra1,iExtra2); + return TRUE; + } + bool processheader( mng_uint32 iWidth, mng_uint32 iHeight ) + { + image->create(iWidth,iHeight,32); + image->setAlphaBuffer(TRUE); + memset(image->bits(),0,iWidth*iHeight*4); + consumer->setSize(iWidth,iHeight); + mng_set_canvasstyle(handle, + QImage::systemByteOrder() == QImage::LittleEndian + ? MNG_CANVAS_BGRA8 : MNG_CANVAS_ARGB8 ); + return TRUE; + } + mng_ptr getcanvasline( mng_uint32 iLinenr ) + { + return image->scanLine(iLinenr); + } + mng_bool refresh( mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h ) + { + QRect r(x,y,w,h); + consumer->changed(r); + consumer->setFramePeriod(0); + consumer->frameDone(); + return TRUE; + } + mng_uint32 gettickcount( ) + { + return timer.elapsed() - losttime; + } + bool settimer( mng_uint32 iMsecs ) + { + consumer->setFramePeriod(iMsecs); + consumer->frameDone(); + state = Time; + losingtimer.start(); + losttime -= iMsecs; + return TRUE; + } + +private: + // Animation-level information + enum { MovieStart, Time, Data, Data2 } state; + + // Image-level information + mng_handle handle; + + // For storing unused data + uchar *buffer; + uint maxbuffer; + uint nbuffer; + + // Timing + QTime timer; + QTime losingtimer; + int losttime; + + void enlargeBuffer(uint n) + { + if ( n > maxbuffer ) { + maxbuffer = n; + buffer = (uchar*)realloc(buffer,n); + } + } + + // Temporary locals during single data-chunk processing + const uchar* data; + uint ndata; + uint ubuffer; + QImageConsumer* consumer; + QImage* image; +}; + +class MNGFormatType : public QImageFormatType +{ + QImageFormat* decoderFor(const uchar* buffer, int length); + const char* formatName() const; +}; + + +/* + \class QMNGFormat qmngio.h + \brief Incremental image decoder for MNG image format. + + \ingroup images + \ingroup graphics + + This subclass of QImageFormat decodes MNG format images, + including animated MNGs. + + Animated MNG images are standard MNG images. The MNG standard + defines two extension chunks that are useful for animations: + +
+
gIFg - GIF-like Graphic Control Extension +
Includes frame disposal, user input flag (we ignore this), + and inter-frame delay. +
gIFx - GIF-like Application Extension +
Multi-purpose, but we just use the Netscape extension + which specifies looping. +
+ + The subimages usually contain a offset chunk (oFFs) but need not. + + The first image defines the "screen" size. Any subsequent image that + doesn't fit is clipped. + +TODO: decide on this point. gIFg gives disposal types, so it can be done. + All images paste (\e not composite, just place all-channel copying) + over the previous image to produce a subsequent frame. +*/ + +/* + \class QMNGFormatType qasyncimageio.h + \brief Incremental image decoder for MNG image format. + + \ingroup images + \ingroup graphics + \ingroup io + + This subclass of QImageFormatType recognizes MNG + format images, creating a QMNGFormat when required. An instance + of this class is created automatically before any other factories, + so you should have no need for such objects. +*/ + +QImageFormat* MNGFormatType::decoderFor( const uchar* buffer, int length ) +{ + if (length < 8) return 0; + + if (buffer[0]==138 // MNG signature + && buffer[1]=='M' + && buffer[2]=='N' + && buffer[3]=='G' + && buffer[4]==13 + && buffer[5]==10 + && buffer[6]==26 + && buffer[7]==10 + || buffer[0]==139 // JNG signature + && buffer[1]=='J' + && buffer[2]=='N' + && buffer[3]=='G' + && buffer[4]==13 + && buffer[5]==10 + && buffer[6]==26 + && buffer[7]==10 +#ifdef QT_NO_IMAGEIO_PNG // if we don't have native PNG support use libmng + || buffer[0]==137 // PNG signature + && buffer[1]=='P' + && buffer[2]=='N' + && buffer[3]=='G' + && buffer[4]==13 + && buffer[5]==10 + && buffer[6]==26 + && buffer[7]==10 +#endif + ) + return new MNGFormat; + return 0; +} + +const char* MNGFormatType::formatName() const +{ + return "MNG"; +} + + +/*! + Constructs a QMNGFormat. +*/ +MNGFormat::MNGFormat() +{ + state = MovieStart; + handle = 0; + nbuffer = 0; + maxbuffer = 0; + buffer = 0; + losttime = 0; +} + +/* + Destroys a QMNGFormat. +*/ +MNGFormat::~MNGFormat() +{ + // We're setting the consumer to 0 since it may have been + // deleted by read_async_image in qimage.cpp + consumer = 0; + if (handle) mng_cleanup(&handle); +} + + +// C-callback to C++-member-function conversion +// +static mng_bool openstream( mng_handle handle ) +{ + return ((MNGFormat*)mng_get_userdata(handle))->openstream(); +} +static mng_bool closestream( mng_handle handle ) +{ + return ((MNGFormat*)mng_get_userdata(handle))->closestream(); +} +static mng_bool readdata( mng_handle handle, mng_ptr pBuf, mng_uint32 iBuflen, mng_uint32p pRead ) +{ + return ((MNGFormat*)mng_get_userdata(handle))->readdata(pBuf,iBuflen,pRead); +} +static mng_bool errorproc( mng_handle handle, + mng_int32 iErrorcode, + mng_int8 iSeverity, + mng_chunkid iChunkname, + mng_uint32 iChunkseq, + mng_int32 iExtra1, + mng_int32 iExtra2, + mng_pchar zErrortext ) +{ + return ((MNGFormat*)mng_get_userdata(handle))->errorproc(iErrorcode, + iSeverity,iChunkname,iChunkseq,iExtra1,iExtra2,zErrortext); +} +static mng_bool processheader( mng_handle handle, + mng_uint32 iWidth, mng_uint32 iHeight ) +{ + return ((MNGFormat*)mng_get_userdata(handle))->processheader(iWidth,iHeight); +} +static mng_ptr getcanvasline( mng_handle handle, mng_uint32 iLinenr ) +{ + return ((MNGFormat*)mng_get_userdata(handle))->getcanvasline(iLinenr); +} +static mng_bool refresh( mng_handle handle, + mng_uint32 iTop, + mng_uint32 iLeft, + mng_uint32 iBottom, + mng_uint32 iRight ) +{ + return ((MNGFormat*)mng_get_userdata(handle))->refresh(iTop,iLeft,iBottom,iRight); +} +static mng_uint32 gettickcount( mng_handle handle ) +{ + return ((MNGFormat*)mng_get_userdata(handle))->gettickcount(); +} +static mng_bool settimer( mng_handle handle, mng_uint32 iMsecs ) +{ + return ((MNGFormat*)mng_get_userdata(handle))->settimer(iMsecs); +} + +static mng_ptr memalloc( mng_size_t iLen ) +{ + return calloc(1,iLen); +} +static void memfree( mng_ptr iPtr, mng_size_t /*iLen*/ ) +{ + free(iPtr); +} + +/*! + This function decodes some data into image changes. + + Returns the number of bytes consumed. +*/ +int MNGFormat::decode( QImage& img, QImageConsumer* cons, + const uchar* buf, int length ) +{ + consumer = cons; + image = &img; + + data = buf; + ndata = length; + ubuffer = 0; + + if ( state == MovieStart ) { + handle = mng_initialize( (mng_ptr)this, Gwenview::memalloc, Gwenview::memfree, 0 ); + mng_set_suspensionmode( handle, MNG_TRUE ); + mng_setcb_openstream( handle, Gwenview::openstream ); + mng_setcb_closestream( handle, Gwenview::closestream ); + mng_setcb_readdata( handle, Gwenview::readdata ); + mng_setcb_errorproc( handle, Gwenview::errorproc ); + mng_setcb_processheader( handle, Gwenview::processheader ); + mng_setcb_getcanvasline( handle, Gwenview::getcanvasline ); + mng_setcb_refresh( handle, Gwenview::refresh ); + mng_setcb_gettickcount( handle, Gwenview::gettickcount ); + mng_setcb_settimer( handle, Gwenview::settimer ); + state = Data; + mng_readdisplay(handle); + losingtimer.start(); + } + + losttime += losingtimer.elapsed(); + bool needmore = false; + if ( ndata ) { + mng_retcode r = mng_display_resume(handle); + needmore = ( r == MNG_NEEDMOREDATA ); + } + losingtimer.start(); + + image = 0; + + nbuffer -= ubuffer; + if ( nbuffer ) { + // Move back unused tail + memcpy(buffer,buffer+ubuffer,nbuffer); + } + // "The function should return without processing all the data if it reaches the end of a frame in the input." + if( ndata && !needmore ) { + length -= ndata; + ndata = 0; + if( length == 0 ) // 0 means done, process at least one byte + length = ndata = 1; + } + if ( ndata ) { + // Not all used. + enlargeBuffer(nbuffer+ndata); + memcpy(buffer+nbuffer,data,ndata); + nbuffer += ndata; + } + + return length; +} + +static MNGFormatType* globalMngFormatTypeObject = 0; + +#endif // QT_NO_ASYNC_IMAGE_IO + +#ifndef QT_NO_ASYNC_IMAGE_IO +void gvCleanupMngIO() +{ + if ( globalMngFormatTypeObject ) { + delete globalMngFormatTypeObject; + globalMngFormatTypeObject = 0; + } +} +#endif + +void gvInitMngIO() +{ + static bool done = FALSE; + if ( !done ) { + done = TRUE; +#ifndef QT_NO_ASYNC_IMAGE_IO + globalMngFormatTypeObject = new MNGFormatType; + qAddPostRoutine( gvCleanupMngIO ); +#endif + } +} + +#else +void gvInitMngIO() {} + +namespace Gwenview { +#endif + +MNG::MNG() { gvInitMngIO(); } +} // namespace diff --git a/src/gvcore/mngformattype.h b/src/gvcore/mngformattype.h new file mode 100644 index 0000000..9e60b64 --- /dev/null +++ b/src/gvcore/mngformattype.h @@ -0,0 +1,55 @@ +// this code is copied from Qt, with fixes for not finishing decoding +// prematurely + +/**************************************************************************** +** +** +** Definition of MNG QImage IOHandler +** +** Created : 970521 +** +** Copyright (C) 2000 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. +** +**********************************************************************/ + +#ifndef QMNGIO_H +#define QMNGIO_H + +#ifndef QT_H +#endif // QT_H +namespace Gwenview { + +class MNG +{ +public: + MNG(); +}; + +} // namespace +#endif // QMNGIO_H diff --git a/src/gvcore/pngformattype.cpp b/src/gvcore/pngformattype.cpp new file mode 100644 index 0000000..36c1064 --- /dev/null +++ b/src/gvcore/pngformattype.cpp @@ -0,0 +1,559 @@ +// this code is copied from Qt, with code added to actually call consumer +// methods that inform about the progress of loading + +/**************************************************************************** +** +** +** Implementation of PNG QImage IOHandler +** +** Created : 970521 +** +** Copyright (C) 1992-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 "pngformattype.h" + +#include + +namespace Gwenview { + +class PNGFormat : public QImageFormat { +public: + PNGFormat(); + virtual ~PNGFormat(); + + int decode(QImage& img, QImageConsumer* consumer, + const uchar* buffer, int length); + + void info(png_structp png_ptr, png_infop info); + void row(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass); + void end(png_structp png_ptr, png_infop info); +#ifdef PNG_USER_CHUNKS_SUPPORTED + int user_chunk(png_structp png_ptr, + png_bytep data, png_uint_32 length); +#endif + +private: + // Animation-level information + enum { MovieStart, FrameStart, Inside, End } state; + int first_frame; + int base_offx; + int base_offy; + + // Image-level information + png_structp png_ptr; + png_infop info_ptr; + + // Temporary locals during single data-chunk processing + QImageConsumer* consumer; + QImage* image; + int unused_data; + QRect changed_rect; +}; + +/* + \class QPNGFormat qpngio.h + \brief The QPNGFormat class provides an incremental image decoder for PNG + image format. + + \ingroup images + \ingroup graphics + + This subclass of QImageFormat decodes PNG format images, + including animated PNGs. + + Animated PNG images are standard PNG images. The PNG standard + defines two extension chunks that are useful for animations: + + \list + \i gIFg - GIF-like Graphic Control Extension. + This includes frame disposal, user input flag (we ignore this), + and inter-frame delay. + \i gIFx - GIF-like Application Extension. + This is multi-purpose, but we just use the Netscape extension + which specifies looping. + \endlist + + The subimages usually contain a offset chunk (oFFs) but need not. + + The first image defines the "screen" size. Any subsequent image that + doesn't fit is clipped. +*/ +/* ###TODO: decide on this point. gIFg gives disposal types, so it can be done. + All images paste (\e not composite, just place all-channel copying) + over the previous image to produce a subsequent frame. +*/ + +/* + \class QPNGFormatType qasyncimageio.h + \brief The QPNGFormatType class provides an incremental image decoder + for PNG image format. + + \ingroup images + \ingroup graphics + \ingroup io + + This subclass of QImageFormatType recognizes PNG format images, creating + a QPNGFormat when required. An instance of this class is created + automatically before any other factories, so you should have no need for + such objects. +*/ + +QImageFormat* PNGFormatType::decoderFor( + const uchar* buffer, int length) +{ + if (length < 8) return 0; + if (buffer[0]==137 + && buffer[1]=='P' + && buffer[2]=='N' + && buffer[3]=='G' + && buffer[4]==13 + && buffer[5]==10 + && buffer[6]==26 + && buffer[7]==10) + return new PNGFormat; + return 0; +} + +const char* PNGFormatType::formatName() const +{ + return "PNG"; +} + +extern "C" { + +static void +info_callback(png_structp png_ptr, png_infop info) +{ + PNGFormat* that = (PNGFormat*)png_get_progressive_ptr(png_ptr); + that->info(png_ptr,info); +} + +static void +row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) +{ + PNGFormat* that = (PNGFormat*)png_get_progressive_ptr(png_ptr); + that->row(png_ptr,new_row,row_num,pass); +} + +static void +end_callback(png_structp png_ptr, png_infop info) +{ + PNGFormat* that = (PNGFormat*)png_get_progressive_ptr(png_ptr); + that->end(png_ptr,info); +} + +#if 0 +#ifdef PNG_USER_CHUNKS_SUPPORTED +static int +CALLBACK_CALL_TYPE user_chunk_callback(png_structp png_ptr, + png_unknown_chunkp chunk) +{ + PNGFormat* that = (PNGFormat*)png_get_progressive_ptr(png_ptr); + return that->user_chunk(png_ptr,chunk->data,chunk->size); +} +#endif +#endif + +static void qt_png_warning(png_structp /*png_ptr*/, png_const_charp message) +{ + qWarning("libpng warning: %s", message); +} + +} + +static +void setup_qt( QImage& image, png_structp png_ptr, png_infop info_ptr ) +{ + // For now, we will use the PC monitor gamma, if you own a Mac, you'd better use 1.8 + const double SCREEN_GAMMA=2.2; + if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA) ) { + double file_gamma; + png_get_gAMA(png_ptr, info_ptr, &file_gamma); + png_set_gamma( png_ptr, SCREEN_GAMMA, file_gamma ); + } + + png_uint_32 width; + png_uint_32 height; + int bit_depth; + int color_type; + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + 0, 0, 0); + + if ( color_type == PNG_COLOR_TYPE_GRAY ) { + // Black & White or 8-bit grayscale + if ( bit_depth == 1 && info_ptr->channels == 1 ) { + png_set_invert_mono( png_ptr ); + png_read_update_info( png_ptr, info_ptr ); + if (!image.create( width, height, 1, 2, QImage::BigEndian )) + return; + image.setColor( 1, qRgb(0,0,0) ); + image.setColor( 0, qRgb(255,255,255) ); + } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + png_set_expand(png_ptr); + png_set_strip_16(png_ptr); + png_set_gray_to_rgb(png_ptr); + + if (!image.create(width, height, 32)) + return; + image.setAlphaBuffer(TRUE); + + if (QImage::systemByteOrder() == QImage::BigEndian) + png_set_swap_alpha(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + } else { + if ( bit_depth == 16 ) + png_set_strip_16(png_ptr); + else if ( bit_depth < 8 ) + png_set_packing(png_ptr); + int ncols = bit_depth < 8 ? 1 << bit_depth : 256; + png_read_update_info(png_ptr, info_ptr); + if (!image.create(width, height, 8, ncols)) + return; + for (int i=0; itrans_values.gray; + if (g < ncols) { + image.setAlphaBuffer(TRUE); + image.setColor(g, image.color(g) & RGB_MASK); + } + } + } + } else if ( color_type == PNG_COLOR_TYPE_PALETTE + && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE) + && info_ptr->num_palette <= 256 ) + { + // 1-bit and 8-bit color + if ( bit_depth != 1 ) + png_set_packing( png_ptr ); + png_read_update_info( png_ptr, info_ptr ); + png_get_IHDR(png_ptr, info_ptr, + &width, &height, &bit_depth, &color_type, 0, 0, 0); + if (!image.create(width, height, bit_depth, info_ptr->num_palette, + QImage::BigEndian)) + return; + int i = 0; + if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ) { + image.setAlphaBuffer( TRUE ); + while ( i < info_ptr->num_trans ) { + image.setColor(i, qRgba( + info_ptr->palette[i].red, + info_ptr->palette[i].green, + info_ptr->palette[i].blue, + info_ptr->trans[i] + ) + ); + i++; + } + } + while ( i < info_ptr->num_palette ) { + image.setColor(i, qRgba( + info_ptr->palette[i].red, + info_ptr->palette[i].green, + info_ptr->palette[i].blue, + 0xff + ) + ); + i++; + } + } else { + // 32-bit + if ( bit_depth == 16 ) + png_set_strip_16(png_ptr); + + png_set_expand(png_ptr); + + if ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) + png_set_gray_to_rgb(png_ptr); + + if (!image.create(width, height, 32)) + return; + + // Only add filler if no alpha, or we can get 5 channel data. + if (!(color_type & PNG_COLOR_MASK_ALPHA) + && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + png_set_filler(png_ptr, 0xff, + QImage::systemByteOrder() == QImage::BigEndian ? + PNG_FILLER_BEFORE : PNG_FILLER_AFTER); + // We want 4 bytes, but it isn't an alpha channel + } else { + image.setAlphaBuffer(TRUE); + } + + if ( QImage::systemByteOrder() == QImage::BigEndian ) { + png_set_swap_alpha(png_ptr); + } + + png_read_update_info(png_ptr, info_ptr); + } + + // Qt==ARGB==Big(ARGB)==Little(BGRA) + if ( QImage::systemByteOrder() == QImage::LittleEndian ) { + png_set_bgr(png_ptr); + } +} + + + +/*! + Constructs a QPNGFormat object. +*/ +PNGFormat::PNGFormat() +{ + state = MovieStart; + first_frame = 1; + base_offx = 0; + base_offy = 0; + png_ptr = 0; + info_ptr = 0; +} + + +/*! + Destroys a QPNGFormat object. +*/ +PNGFormat::~PNGFormat() +{ + if ( png_ptr ) + png_destroy_read_struct(&png_ptr, &info_ptr, 0); +} + + +/*! + This function decodes some data into image changes. + + Returns the number of bytes consumed. +*/ +int PNGFormat::decode(QImage& img, QImageConsumer* cons, + const uchar* buffer, int length) +{ + consumer = cons; + image = &img; + + if ( state != Inside ) { + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (!png_ptr) { + info_ptr = 0; + image = 0; + return -1; + } + + png_set_error_fn(png_ptr, 0, 0, qt_png_warning); + png_set_compression_level(png_ptr, 9); + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, &info_ptr, 0); + image = 0; + return -1; + } + + if (setjmp((png_ptr)->jmpbuf)) { + png_destroy_read_struct(&png_ptr, &info_ptr, 0); + image = 0; + return -1; + } + + png_set_progressive_read_fn(png_ptr, (void *)this, + info_callback, row_callback, end_callback); + +#ifdef PNG_USER_CHUNKS_SUPPORTED + // Can't do this yet. libpng has a crash bug with unknown (user) chunks. + // Warwick has sent them a patch. + // png_set_read_user_chunk_fn(png_ptr, 0, user_chunk_callback); + // png_set_keep_unknown_chunks(png_ptr, 2/*HANDLE_CHUNK_IF_SAFE*/, 0, 0); +#endif + + if ( state != MovieStart && *buffer != 0211 ) { + // Good, no signature - the preferred way to concat PNG images. + // Skip them. + png_set_sig_bytes(png_ptr, 8); + } + + state = Inside; + changed_rect = QRect(); + } + + if ( !png_ptr ) return 0; + + if (setjmp(png_ptr->jmpbuf)) { + png_destroy_read_struct(&png_ptr, &info_ptr, 0); + image = 0; + state = MovieStart; + return -1; + } + unused_data = 0; + png_process_data(png_ptr, info_ptr, (png_bytep)buffer, length); + int l = length - unused_data; + + if( !changed_rect.isNull()) { + consumer->changed( changed_rect ); + changed_rect = QRect(); + } + + if ( state != Inside ) { + if ( png_ptr ) + png_destroy_read_struct(&png_ptr, &info_ptr, 0); + } + + image = 0; + return l; +} + +void PNGFormat::info(png_structp png, png_infop) +{ + png_set_interlace_handling(png); + setup_qt(*image, png, info_ptr); + consumer->setSize( image->width(), image->height()); +} + +void PNGFormat::row(png_structp png, png_bytep new_row, + png_uint_32 row_num, int) +{ + uchar* old_row = image->scanLine(row_num); + png_progressive_combine_row(png, old_row, new_row); + changed_rect |= QRect( 0, row_num, image->width(), 1 ); +} + + +void PNGFormat::end(png_structp png, png_infop info) +{ + int offx = png_get_x_offset_pixels(png,info) - base_offx; + int offy = png_get_y_offset_pixels(png,info) - base_offy; + if ( first_frame ) { + base_offx = offx; + base_offy = offy; + first_frame = 0; + } + image->setOffset(QPoint(offx,offy)); + image->setDotsPerMeterX(png_get_x_pixels_per_meter(png,info)); + image->setDotsPerMeterY(png_get_y_pixels_per_meter(png,info)); + png_textp text_ptr; + int num_text=0; + png_get_text(png,info,&text_ptr,&num_text); + while (num_text--) { + image->setText(text_ptr->key,0,text_ptr->text); + text_ptr++; + } + if( !changed_rect.isNull()) { + consumer->changed( changed_rect ); + changed_rect = QRect(); + } + QRect r(0,0,image->width(),image->height()); + consumer->frameDone(QPoint(offx,offy),r); + consumer->end(); + state = FrameStart; + unused_data = (int)png->buffer_size; // Since libpng doesn't tell us +} + +#ifdef PNG_USER_CHUNKS_SUPPORTED + +/* +#ifndef QT_NO_IMAGE_TEXT +static bool skip(png_uint_32& max, png_bytep& data) +{ + while (*data) { + if ( !max ) return FALSE; + max--; + data++; + } + if ( !max ) return FALSE; + max--; + data++; // skip to after NUL + return TRUE; +} +#endif +*/ + +int PNGFormat::user_chunk(png_structp png, + png_bytep data, png_uint_32 length) +{ +#if 0 // NOT SUPPORTED: experimental PNG animation. + // qDebug("Got %ld-byte %s chunk", length, png->chunk_name); + if ( 0==qstrcmp((char*)png->chunk_name, "gIFg") + && length == 4 ) { + + //QPNGImageWriter::DisposalMethod disposal = + // (QPNGImageWriter::DisposalMethod)data[0]; + // ### TODO: use the disposal method + int ms_delay = ((data[2] << 8) | data[3])*10; + consumer->setFramePeriod(ms_delay); + return 1; + } else if ( 0==qstrcmp((char*)png->chunk_name, "gIFx") + && length == 13 ) { + if ( qstrncmp((char*)data,"NETSCAPE2.0",11)==0 ) { + int looping = (data[0xC]<<8)|data[0xB]; + consumer->setLooping(looping); + return 1; + } + } +#else + Q_UNUSED( png ) + Q_UNUSED( data ) + Q_UNUSED( length ) +#endif + + /* + + libpng now supports this chunk. + + + if ( 0==qstrcmp((char*)png->chunk_name, "iTXt") && length>=6 ) { + const char* keyword = (const char*)data; + if ( !skip(length,data) ) return 0; + if ( length >= 4 ) { + char compression_flag = *data++; + char compression_method = *data++; + if ( compression_flag == compression_method ) { + // fool the compiler into thinking they're used + } + const char* lang = (const char*)data; + if ( !skip(length,data) ) return 0; + // const char* keyword_utf8 = (const char*)data; + if ( !skip(length,data) ) return 0; + const char* text_utf8 = (const char*)data; + if ( !skip(length,data) ) return 0; + QString text = QString::fromUtf8(text_utf8); + image->setText(keyword,lang[0] ? lang : 0,text); + return 1; + } + } + */ + + return 0; +} +} // namespace +#endif diff --git a/src/gvcore/pngformattype.h b/src/gvcore/pngformattype.h new file mode 100644 index 0000000..920ee0c --- /dev/null +++ b/src/gvcore/pngformattype.h @@ -0,0 +1,63 @@ +// this code is copied from Qt, with code added to actually call consumer +// methods that inform about the progress of loading + +/**************************************************************************** +** +** +** Implementation of PNG QImage IOHandler +** +** Created : 970521 +** +** Copyright (C) 1992-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. +** +**********************************************************************/ + +#ifndef gvpngformattype_h +#define gvpngformattype_h + +#include + +namespace Gwenview { + +/** + * @internal + * + * An incremental loader factory for PNG's. + */ +class PNGFormatType : public QImageFormatType { +public: + QImageFormat* decoderFor(const uchar* buffer, int length); + const char* formatName() const; +}; + +} // namespace + +// ----------------------------------------------------------------------------- + +#endif // gvpngformattype_h diff --git a/src/gvcore/printdialog.cpp b/src/gvcore/printdialog.cpp new file mode 100644 index 0000000..6e3a162 --- /dev/null +++ b/src/gvcore/printdialog.cpp @@ -0,0 +1,297 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - printing support +Copyright (c) 2003 Angelo Naselli + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Qt +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include + +// Local +#include "document.h" +#include "printdialogpagebase.h" +#include "printdialog.moc" + +namespace Gwenview { + + +const char* STR_TRUE="true"; +const char* STR_FALSE="false"; + +static inline Unit stringToUnit(const QString& unit) { + if (unit == i18n("Millimeters")) { + return GV_MILLIMETERS; + } else if (unit == i18n("Centimeters")) { + return GV_CENTIMETERS; + } else {//Inches + return GV_INCHES; + } +} + +static inline QString unitToString(Unit unit) { + if (unit == GV_MILLIMETERS) { + return i18n("Millimeters"); + } else if (unit == GV_CENTIMETERS) { + return i18n("Centimeters"); + } else { //GV_INCHES + return i18n("Inches"); + } +} + + +static inline double unitToMM(Unit unit) { + if (unit == GV_MILLIMETERS) { + return 1.; + } else if (unit == GV_CENTIMETERS) { + return 10.; + } else { //GV_INCHES + return 25.4; + } +} + + +PrintDialogPage::PrintDialogPage( Document* document, QWidget *parent, const char *name ) + : KPrintDialogPage( parent, name ) { + mDocument = document; + mContent = new PrintDialogPageBase(this); + setTitle( mContent->caption() ); + + QVBoxLayout *layout = new QVBoxLayout( this ); + layout->addWidget( mContent ); + + connect(mContent->mWidth, SIGNAL( valueChanged( double )), SLOT( slotWidthChanged( double ))); + connect(mContent->mHeight, SIGNAL( valueChanged( double )), SLOT( slotHeightChanged( double ))); + connect(mContent->mKeepRatio, SIGNAL( toggled( bool )), SLOT( toggleRatio( bool ))); + connect(mContent->mUnit, SIGNAL(activated(const QString &)), SLOT(slotUnitChanged(const QString& ))); + + mPreviousUnit = GV_MILLIMETERS; +} + +PrintDialogPage::~PrintDialogPage() {} + +void PrintDialogPage::getOptions( QMap& opts, bool /*incldef*/ ) { + opts["app-gwenview-position"] = QString::number(getPosition(mContent->mPosition->currentText())); + opts["app-gwenview-printFilename"] = mContent->mAddFileName->isChecked() ? STR_TRUE : STR_FALSE; + opts["app-gwenview-printComment"] = mContent->mAddComment->isChecked() ? STR_TRUE : STR_FALSE; + opts["app-gwenview-scale"] = QString::number( + mContent->mNoScale->isChecked() ? GV_NOSCALE + : mContent->mFitToPage->isChecked() ? GV_FITTOPAGE + : GV_SCALE); + opts["app-gwenview-fitToPage"] = mContent->mFitToPage->isChecked() ? STR_TRUE : STR_FALSE; + opts["app-gwenview-enlargeToFit"] = mContent->mEnlargeToFit->isChecked() ? STR_TRUE : STR_FALSE; + + opts["app-gwenview-scaleKeepRatio"] = mContent->mKeepRatio->isChecked() ? STR_TRUE : STR_FALSE; + opts["app-gwenview-scaleUnit"] = QString::number(stringToUnit(mContent->mUnit->currentText())); + opts["app-gwenview-scaleWidth"] = QString::number( scaleWidth() ); + opts["app-gwenview-scaleHeight"] = QString::number( scaleHeight() ); + +} + +void PrintDialogPage::setOptions( const QMap& opts ) { + int val; + bool ok; + QString stVal; + + val = opts["app-gwenview-position"].toInt( &ok ); + if (ok) { + stVal = setPosition(val); + mContent->mPosition->setCurrentItem(stVal); + } + + mContent->mAddFileName->setChecked( opts["app-gwenview-printFilename"] == STR_TRUE ); + mContent->mAddComment->setChecked( opts["app-gwenview-printComment"] == STR_TRUE ); + // Starts from id 1 because 0 is returned if not ok, and seems to have a weird + // problem with id 2 (last id) otherwise :( + ScaleId scaleButtonId = static_cast( opts["app-gwenview-scale"].toInt( &ok ) ); + if (ok) { + mContent->mScaleGroup->setButton( scaleButtonId ); + } else { + mContent->mScaleGroup->setButton( GV_NOSCALE ); + } + mContent->mEnlargeToFit->setChecked( opts["app-gwenview-enlargeToFit"] == STR_TRUE ); + + Unit unit = static_cast( opts["app-gwenview-scaleUnit"].toInt( &ok ) ); + if (ok) { + stVal = unitToString(unit); + mContent->mUnit->setCurrentItem(stVal); + mPreviousUnit = unit; + } + + mContent->mKeepRatio->setChecked( opts["app-gwenview-scaleKeepRatio"] == STR_TRUE ); + + double dbl; + dbl = opts["app-gwenview-scaleWidth"].toDouble( &ok ); + if ( ok ) setScaleWidth( dbl ); + dbl = opts["app-gwenview-scaleHeight"].toDouble( &ok ); + if ( ok ) setScaleHeight( dbl ); +} + +double PrintDialogPage::scaleWidth() const { + return mContent->mWidth->value(); +} + +double PrintDialogPage::scaleHeight() const { + return mContent->mHeight->value(); +} + +void PrintDialogPage::setScaleWidth( double value ) { + mContent->mWidth->setValue(value); +} + +void PrintDialogPage::setScaleHeight( double value ) { + mContent->mHeight->setValue(value); +} + +int PrintDialogPage::getPosition(const QString& align) { + int alignment; + + if (align == i18n("Central-Left")) { + alignment = Qt::AlignLeft | Qt::AlignVCenter; + } else if (align == i18n("Central-Right")) { + alignment = Qt::AlignRight | Qt::AlignVCenter; + } else if (align == i18n("Top-Left")) { + alignment = Qt::AlignTop | Qt::AlignLeft; + } else if (align == i18n("Top-Right")) { + alignment = Qt::AlignTop | Qt::AlignRight; + } else if (align == i18n("Bottom-Left")) { + alignment = Qt::AlignBottom | Qt::AlignLeft; + } else if (align == i18n("Bottom-Right")) { + alignment = Qt::AlignBottom | Qt::AlignRight; + } else if (align == i18n("Top-Central")) { + alignment = Qt::AlignTop | Qt::AlignHCenter; + } else if (align == i18n("Bottom-Central")) { + alignment = Qt::AlignBottom | Qt::AlignHCenter; + } else { + // Central + alignment = Qt::AlignCenter; // Qt::AlignHCenter || Qt::AlignVCenter + } + + return alignment; +} + +QString PrintDialogPage::setPosition(int align) { + QString alignment; + + if (align == (Qt::AlignLeft | Qt::AlignVCenter)) { + alignment = i18n("Central-Left"); + } else if (align == (Qt::AlignRight | Qt::AlignVCenter)) { + alignment = i18n("Central-Right"); + } else if (align == (Qt::AlignTop | Qt::AlignLeft)) { + alignment = i18n("Top-Left"); + } else if (align == (Qt::AlignTop | Qt::AlignRight)) { + alignment = i18n("Top-Right"); + } else if (align == (Qt::AlignBottom | Qt::AlignLeft)) { + alignment = i18n("Bottom-Left"); + } else if (align == (Qt::AlignBottom | Qt::AlignRight)) { + alignment = i18n("Bottom-Right"); + } else if (align == (Qt::AlignTop | Qt::AlignHCenter)) { + alignment = i18n("Top-Central"); + } else if (align == (Qt::AlignBottom | Qt::AlignHCenter)) { + alignment = i18n("Bottom-Central"); + } else { + // Central: Qt::AlignCenter or (Qt::AlignHCenter || Qt::AlignVCenter) + alignment = i18n("Central"); + } + + return alignment; +} + +// SLOTS +void PrintDialogPage::slotHeightChanged (double value) { + mContent->mWidth->blockSignals(true); + mContent->mHeight->blockSignals(true); + + if (mContent->mKeepRatio->isChecked()) { + double width = (mDocument->width() * value) / mDocument->height(); + mContent->mWidth->setValue( width ? width : 1.); + } + mContent->mHeight->setValue(value); + + mContent->mWidth->blockSignals(false); + mContent->mHeight->blockSignals(false); + +} + +void PrintDialogPage::slotWidthChanged (double value) { + mContent->mWidth->blockSignals(true); + mContent->mHeight->blockSignals(true); + if (mContent->mKeepRatio->isChecked()) { + double height = (mDocument->height() * value) / mDocument->width(); + mContent->mHeight->setValue( height ? height : 1); + } + mContent->mWidth->setValue(value); + mContent->mWidth->blockSignals(false); + mContent->mHeight->blockSignals(false); +} + +void PrintDialogPage::toggleRatio(bool enable) { + if (!enable) return; + // choosing a startup value of 15x10 cm (common photo dimention) + // mContent->mHeight->value() or mContent->mWidth->value() + // are usually empty at startup and hxw (0x0) isn't good IMO keeping ratio + double hValue, wValue; + if (mDocument->height() > mDocument->width()) { + hValue = mContent->mHeight->value(); + if (!hValue) hValue = 150*unitToMM(mPreviousUnit); + wValue = (mDocument->width() * hValue)/ mDocument->height(); + } else { + wValue = mContent->mWidth->value(); + if (!wValue) wValue = 150*unitToMM(mPreviousUnit); + hValue = (mDocument->height() * wValue)/ mDocument->width(); + } + + mContent->mWidth->blockSignals(true); + mContent->mHeight->blockSignals(true); + mContent->mWidth->setValue(wValue); + mContent->mHeight->setValue(hValue); + mContent->mWidth->blockSignals(false); + mContent->mHeight->blockSignals(false); +} + + +void PrintDialogPage::slotUnitChanged(const QString& string) { + Unit newUnit = stringToUnit(string); + double ratio = unitToMM(mPreviousUnit) / unitToMM(newUnit); + + mContent->mWidth->blockSignals(true); + mContent->mHeight->blockSignals(true); + + mContent->mWidth->setValue( mContent->mWidth->value() * ratio); + mContent->mHeight->setValue( mContent->mHeight->value() * ratio); + + mContent->mWidth->blockSignals(false); + mContent->mHeight->blockSignals(false); + + mPreviousUnit = newUnit; +} + + + + +} // namespace diff --git a/src/gvcore/printdialog.h b/src/gvcore/printdialog.h new file mode 100644 index 0000000..261583f --- /dev/null +++ b/src/gvcore/printdialog.h @@ -0,0 +1,80 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - printing support +Copyright (c) 2003 Angelo Naselli + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef PRINTDIALOG_H +#define PRINTDIALOG_H + +//Qt +#include +#include + +// KDE +#include +#include + +#include "libgwenview_export.h" +class PrintDialogPageBase; +namespace Gwenview { +class Document; + +enum Unit { + GV_MILLIMETERS = 1, + GV_CENTIMETERS, + GV_INCHES +}; + +enum ScaleId { + GV_NOSCALE=1, + GV_FITTOPAGE, + GV_SCALE +}; + +class LIBGWENVIEW_EXPORT PrintDialogPage : public KPrintDialogPage { + Q_OBJECT + +public: + PrintDialogPage( Document* document, QWidget *parent = 0L, const char *name = 0 ); + ~PrintDialogPage(); + + virtual void getOptions(QMap& opts, bool incldef = false); + virtual void setOptions(const QMap& opts); + +private slots: + void toggleRatio(bool enable); + void slotUnitChanged(const QString& string); + void slotHeightChanged(double value); + void slotWidthChanged(double value); + +private: + double scaleWidth() const; + double scaleHeight() const; + void setScaleWidth(double pixels); + void setScaleHeight(double pixels); + int getPosition(const QString& align); + QString setPosition(int align); + + Document *mDocument; + PrintDialogPageBase* mContent; + Unit mPreviousUnit; +}; + +} // namespace +#endif + diff --git a/src/gvcore/printdialogpagebase.ui b/src/gvcore/printdialogpagebase.ui new file mode 100644 index 0000000..f5d5c8c --- /dev/null +++ b/src/gvcore/printdialogpagebase.ui @@ -0,0 +1,408 @@ + +PrintDialogPageBase + + + PrintDialogPageBase + + + + 0 + 0 + 511 + 260 + + + + Image Settings + + + + unnamed + + + 0 + + + + layout2 + + + + unnamed + + + + textLabel1 + + + Image position: + + + + + + Top-Left + + + + + Top-Central + + + + + Top-Right + + + + + Central-Left + + + + + Central + + + + + Central-Right + + + + + Bottom-Left + + + + + Bottom-Central + + + + + Bottom-Right + + + + mPosition + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 101 + 21 + + + + + + + + mAddFileName + + + Print fi&lename below image + + + true + + + + + mAddComment + + + Print image comment + + + + + + + + mScaleGroup + + + Scaling + + + + unnamed + + + + mNoScale + + + &No scaling + + + true + + + 1 + + + + + mFitToPage + + + &Fit image to page + + + false + + + 2 + + + + + layout4 + + + + unnamed + + + + spacer4 + + + Horizontal + + + Fixed + + + + 20 + 20 + + + + + + mEnlargeToFit + + + false + + + Enlarge smaller images + + + + + spacer6 + + + Horizontal + + + Expanding + + + + 240 + 21 + + + + + + + + mScale + + + &Scale to: + + + 3 + + + + + layout4 + + + + unnamed + + + + spacer4_2 + + + Horizontal + + + Fixed + + + + 20 + 20 + + + + + + mWidth + + + false + + + 1e+06 + + + 1 + + + false + + + 2 + + + + + textLabel2 + + + x + + + + + mHeight + + + false + + + 1e+06 + + + 1 + + + false + + + 2 + + + + + + Millimeters + + + + + Centimeters + + + + + Inches + + + + mUnit + + + false + + + + + mKeepRatio + + + false + + + Keep ratio + + + + + spacer2 + + + Horizontal + + + Expanding + + + + 16 + 20 + + + + + + + + + + + + + + mScale + toggled(bool) + mUnit + setEnabled(bool) + + + mScale + toggled(bool) + mKeepRatio + setEnabled(bool) + + + mFitToPage + toggled(bool) + mEnlargeToFit + setEnabled(bool) + + + mScale + toggled(bool) + mWidth + setEnabled(bool) + + + mScale + toggled(bool) + mHeight + setEnabled(bool) + + + + + kcombobox.h + knuminput.h + knuminput.h + kcombobox.h + + diff --git a/src/gvcore/qxcfi.cpp b/src/gvcore/qxcfi.cpp new file mode 100644 index 0000000..2a771bc --- /dev/null +++ b/src/gvcore/qxcfi.cpp @@ -0,0 +1,2405 @@ +/* + * qxcfi.cpp: A Qt 3 plug-in for reading GIMP XCF image files + * Copyright (C) 2001 lignum Computing, Inc. + * $Id: qxcfi.cpp 531593 2006-04-19 15:46:52Z gateau $ + * + * This plug-in 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.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include "qxcfi.h" + + +// Change a QRgb value's alpha only. (an optimization) +inline QRgb qRgba ( QRgb rgb, int a ) +{ + return ( ( a & 0xff ) << 24 | ( rgb & RGB_MASK ) ); +} + + +namespace Gwenview { + +int SafeDataStream::at() const { + return mDevice->at(); +} + +const float INCHESPERMETER = (100. / 2.54); + +// Static global values + +int XCFImageFormat::random_table[RANDOM_TABLE_SIZE]; + +int XCFImageFormat::add_lut[256][256]; + +XCFImageFormat::LayerModes XCFImageFormat::layer_modes[] = { + { true }, // NORMAL_MODE + { true }, // DISSOLVE_MODE + { true }, // BEHIND_MODE + { false }, // MULTIPLY_MODE + { false }, // SCREEN_MODE + { false }, // OVERLAY_MODE + { false }, // DIFFERENCE_MODE + { false }, // ADDITION_MODE + { false }, // SUBTRACT_MODE + { false }, // DARKEN_ONLY_MODE + { false }, // LIGHTEN_ONLY_MODE + { false }, // HUE_MODE + { false }, // SATURATION_MODE + { false }, // COLOR_MODE + { false }, // VALUE_MODE + { false }, // DIVIDE_MODE + { true }, // ERASE_MODE + { true }, // REPLACE_MODE + { true }, // ANTI_ERASE_MODE +}; + +////////////////////////////////////////////////////////////////////////////////// +// From GIMP "paint_funcs.c" v1.2 + +/*! + * Multiply two color components. Really expects the arguments to be + * 8-bit quantities. + * \param a first minuend. + * \param b second minuend. + * \return product of arguments. + */ +inline int INT_MULT ( int a, int b ) +{ + int c = a * b + 0x80; + return ( ( c >> 8 ) + c ) >> 8; +} + +/*! + * Blend the two color components in the proportion alpha: + * + * result = alpha a + ( 1 - alpha b) + * + * \param a first component. + * \param b second component. + * \param alpha blend proportion. + * \return blended color components. + */ + +inline int INT_BLEND ( int a, int b, int alpha ) +{ + return INT_MULT( a - b, alpha ) + b; +} + +// Actually from GLIB + +inline int MIN ( int a, int b ) +{ + return ( a < b ? a : b ); +} + +inline int MAX ( int a, int b ) +{ + return ( a > b ? a : b ); +} + +// From GIMP "gimpcolorspace.c" v1.2 + +/*! + * Convert a color in RGB space to HSV space (Hue, Saturation, Value). + * \param red the red component (modified in place). + * \param green the green component (modified in place). + * \param blue the blue component (modified in place). + */ +void RGBTOHSV ( uchar& red, uchar& green, uchar& blue ) +{ + int r, g, b; + double h, s, v; + int min, max; + + h = 0.; + + r = red; + g = green; + b = blue; + + if ( r > g ) { + max = MAX( r, b ); + min = MIN( g, b ); + } + else { + max = MAX( g, b ); + min = MIN( r, b ); + } + + v = max; + + if ( max != 0 ) + s = ( ( max - min ) * 255 ) / (double)max; + else + s = 0; + + if ( s == 0 ) + h = 0; + else { + int delta = max - min; + if ( r == max ) + h = ( g - b ) / (double)delta; + else if ( g == max ) + h = 2 + ( b - r ) / (double)delta; + else if ( b == max ) + h = 4 + ( r - g ) / (double)delta; + h *= 42.5; + + if ( h < 0 ) + h += 255; + if ( h > 255 ) + h -= 255; + } + + red = (uchar)h; + green = (uchar)s; + blue = (uchar)v; +} + +/*! + * Convert a color in HSV space to RGB space. + * \param hue the hue component (modified in place). + * \param saturation the saturation component (modified in place). + * \param value the value component (modified in place). + */ +void HSVTORGB ( uchar& hue, uchar& saturation, uchar& value ) +{ + if ( saturation == 0 ) { + hue = value; + saturation = value; + value = value; + } + else { + double h = hue * 6. / 255.; + double s = saturation / 255.; + double v = value / 255.; + + double f = h - (int)h; + double p = v * ( 1. - s ); + double q = v * ( 1. - ( s * f ) ); + double t = v * ( 1. - ( s * ( 1. - f ) ) ); + + // Worth a note here that gcc 2.96 will generate different results + // depending on optimization mode on i386. + + switch ((int)h) { + case 0: + hue = (uchar)( v * 255 ); + saturation = (uchar)( t * 255 ); + value = (uchar)( p * 255 ); + break; + case 1: + hue = (uchar)( q * 255 ); + saturation = (uchar)( v * 255 ); + value = (uchar)( p * 255 ); + break; + case 2: + hue = (uchar)( p * 255 ); + saturation = (uchar)( v * 255 ); + value = (uchar)( t * 255 ); + break; + case 3: + hue = (uchar)( p * 255 ); + saturation = (uchar)( q * 255 ); + value = (uchar)( v * 255 ); + break; + case 4: + hue = (uchar)( t * 255 ); + saturation = (uchar)( p * 255 ); + value = (uchar)( v * 255 ); + break; + case 5: + hue = (uchar)( v * 255 ); + saturation = (uchar)( p * 255 ); + value = (uchar)( q * 255 ); + } + } +} + +/*! + * Convert a color in RGB space to HLS space (Hue, Lightness, Saturation). + * \param red the red component (modified in place). + * \param green the green component (modified in place). + * \param blue the blue component (modified in place). + */ +void RGBTOHLS ( uchar& red, uchar& green, uchar& blue ) +{ + int r = red; + int g = green; + int b = blue; + + int min, max; + + if ( r > g ) { + max = MAX( r, b ); + min = MIN( g, b ); + } + else { + max = MAX( g, b ); + min = MIN( r, b ); + } + + double h; + double l = ( max + min ) / 2.; + double s; + + if ( max == min ) { + s = 0.; + h = 0.; + } + else { + int delta = max - min; + + if ( l < 128 ) + s = 255 * (double)delta / (double)( max + min ); + else + s = 255 * (double)delta / (double)( 511 - max - min ); + + if ( r == max ) + h = ( g - b ) / (double)delta; + else if ( g == max ) + h = 2 + ( b - r ) / (double)delta; + else + h = 4 + ( r - g ) / (double)delta; + + h *= 42.5; + + if ( h < 0 ) + h += 255; + else if ( h > 255 ) + h -= 255; + } + + red = (uchar)h; + green = (uchar)l; + blue = (uchar)s; +} + +/*! + * Implement the HLS "double hex-cone". + * \param n1 lightness fraction (?) + * \param n2 saturation fraction (?) + * \param hue hue "angle". + * \return HLS value. + */ +int HLSVALUE ( double n1, double n2, double hue ) +{ + double value; + + if ( hue > 255 ) + hue -= 255; + else if ( hue < 0 ) + hue += 255; + + if ( hue < 42.5 ) + value = n1 + ( n2 - n1 ) * ( hue / 42.5 ); + else if ( hue < 127.5 ) + value = n2; + else if ( hue < 170 ) + value = n1 + ( n2 - n1 ) * ( ( 170 - hue ) / 42.5 ); + else + value = n1; + + return (int)( value * 255 ); +} + +/*! + * Convert a color in HLS space to RGB space. + * \param hue the hue component (modified in place). + * \param lightness the lightness component (modified in place). + * \param saturation the saturation component (modified in place). + */ +void HLSTORGB ( uchar& hue, uchar& lightness, uchar& saturation ) +{ + double h = hue; + double l = lightness; + double s = saturation; + + if ( s == 0 ) { + hue = (uchar)l; + lightness = (uchar)l; + saturation = (uchar)l; + } + else { + double m1, m2; + + if ( l < 128 ) + m2 = ( l * ( 255 + s ) ) / 65025.; + else + m2 = ( l + s - ( l * s ) / 255. ) / 255.; + + m1 = ( l / 127.5 ) - m2; + + hue = HLSVALUE( m1, m2, h + 85 ); + lightness = HLSVALUE( m1, m2, h ); + saturation = HLSVALUE( m1, m2, h - 85 ); + } +} +////////////////////////////////////////////////////////////////////////////////// + + +XCFImageFormat::XCFImageFormat() { + // From GIMP "paint_funcs.c" v1.2 + srand( RANDOM_SEED ); + + for ( int i = 0; i < RANDOM_TABLE_SIZE; i++ ) + random_table[i] = rand(); + + for ( int i = 0; i < RANDOM_TABLE_SIZE; i++ ) { + int tmp; + int swap = i + rand() % ( RANDOM_TABLE_SIZE - i ); + tmp = random_table[i]; + random_table[i] = random_table[swap]; + random_table[swap] = tmp; + } + + for ( int j = 0; j < 256; j++ ) { + for ( int k = 0; k < 256; k++ ) { + int tmp_sum = j + k; + if ( tmp_sum > 255 ) + tmp_sum = 255; + add_lut[j][k] = tmp_sum; + } + } + } + + +bool XCFImageFormat::installIOHandler ( const QString& ) { + QImageIO::defineIOHandler( "XCF", "gimp xcf", 0, + &XCFImageFormat::readXCF, +#ifdef TMP_WRITE + &XCFImageFormat::writeXCF ); +#else + 0 ); +#endif + return true; +} + + +void XCFImageFormat::registerFormat() { + QImageIO::defineIOHandler( "XCF","^gimp xcf", + 0,XCFImageFormat::readXCF,0L); +} + + +/*! + * The Qt QImageIO architecture invokes this routine to read the image. + * The file (or other data stream) is already open and the + * initial string indicating a XCF file has been matched (but the stream + * is positioned at its beginning). + * + * The XCF file is binary and is stored in big endian format. The + * SafeDataStream class is used to read the file. Even though the XCF file + * was not written with SafeDataStream, there is still a good match. At least + * in version 001 of XCF and version 4 of SafeDataStream. Any other combination + * is suspect. + * + * Any failures while reading the XCF image are reported by the + * QImage::status() method. + * + * \param image_io the QImageIO object connected to the XCF image. + */ +void XCFImageFormat::readXCF ( QImageIO* image_io ) +{ + XCFImage xcf_image; + + // The XCF data is stored in big endian format, which SafeDataStream handles + // very well. + + SafeDataStream xcf_io( image_io->ioDevice() ); + + char tag[14]; + xcf_io.readRawBytes( tag, sizeof(tag) ); + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on header tag" ); + return; + } + + xcf_io >> xcf_image.width >> xcf_image.height >> xcf_image.type; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on image info" ); + return; + } + + if ( !loadImageProperties( xcf_io, xcf_image ) ) return; + + // The layers appear to be stored in top-to-bottom order. This is + // the reverse of how a merged image must be computed. So, the layer + // offsets are pushed onto a LIFO stack (thus, we don't have to load + // all the data of all layers before beginning to construct the + // merged image). + + QValueStack< Q_INT32 > layer_offsets; + + while ( true ) { + Q_INT32 layer_offset; + + xcf_io >> layer_offset; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on layer offsets" ); + return; + } + + if ( layer_offset == 0 ) break; + + layer_offsets.push( layer_offset ); + } + + xcf_image.num_layers = layer_offsets.size(); + + if ( layer_offsets.size() == 0 ) { + qDebug( "XCF: no layers!" ); + return; + } + + // Load each layer and add it to the image + + while ( !layer_offsets.isEmpty() ) { + Q_INT32 layer_offset = layer_offsets.pop(); + + xcf_io.device()->at( layer_offset ); + + if ( !loadLayer( xcf_io, xcf_image ) ) return; + } + + if ( !xcf_image.initialized ) { + qDebug( "XCF: no visible layers!" ); + return; + } + + image_io->setImage( xcf_image.image ); + image_io->setStatus( 0 ); +} + +/*! + * Construct the QImage which will eventually be returned to the QImage + * loader. + * + * There are a couple of situations which require that the QImage is not + * exactly the same as The GIMP's representation. The full table is: + * \verbatim + * Grayscale opaque : 8 bpp indexed + * Grayscale translucent : 32 bpp + alpha + * Indexed opaque : 1 bpp if num_colors <= 2 + * : 8 bpp indexed otherwise + * Indexed translucent : 8 bpp indexed + alpha if num_colors < 256 + * : 32 bpp + alpha otherwise + * RGB opaque : 32 bpp + * RGBA translucent : 32 bpp + alpha + * \endverbatim + * Whether the image is translucent or not is determined by the bottom layer's + * alpha channel. However, even if the bottom layer lacks an alpha channel, + * it can still have an opacity < 1. In this case, the QImage is promoted + * to 32-bit. (Note this is different from the output from the GIMP image + * exporter, which seems to ignore this attribute.) + * + * Independently, higher layers can be translucent, but the background of + * the image will not show through if the bottom layer is opaque. + * + * For indexed images, translucency is an all or nothing effect. + * \param xcf_image contains image info and bottom-most layer. + */ +void XCFImageFormat::initializeImage ( XCFImage& xcf_image ) +{ + // (Aliases to make the code look a little better.) + Layer& layer( xcf_image.layer ); + QImage& image( xcf_image.image ); + + switch ( layer.type ) { + case RGB_GIMAGE: + if ( layer.opacity == OPAQUE_OPACITY ) { + image.create( xcf_image.width, xcf_image.height, 32 ); + image.fill( qRgb( 255, 255, 255 ) ); + break; + } // else, fall through to 32-bit representation + + case RGBA_GIMAGE: + image.create( xcf_image.width, xcf_image.height, 32 ); + image.fill( qRgba( 255, 255, 255, 0 ) ); + // Turning this on prevents fill() from affecting the alpha channel, + // by the way. + image.setAlphaBuffer( true ); + break; + + case GRAY_GIMAGE: + if ( layer.opacity == OPAQUE_OPACITY ) { + image.create( xcf_image.width, xcf_image.height, 8, 256 ); + setGrayPalette( image ); + image.fill( 255 ); + break; + } // else, fall through to 32-bit representation + + case GRAYA_GIMAGE: + image.create( xcf_image.width, xcf_image.height, 32 ); + image.fill( qRgba( 255, 255, 255, 0 ) ); + image.setAlphaBuffer( true ); + break; + + case INDEXED_GIMAGE: + // As noted in the table above, there are quite a few combinations + // which are possible with indexed images, depending on the + // presence of transparency (note: not translucency, which is not + // supported by The GIMP for indexed images) and the number of + // individual colors. + + // Note: Qt treats a bitmap with a Black and White color palette + // as a mask, so only the "on" bits are drawn, regardless of the + // order color table entries. Otherwise (i.e., at least one of the + // color table entries is not black or white), it obeys the one- + // or two-color palette. Have to ask about this... + + if ( xcf_image.num_colors <= 2 ) { + image.create( xcf_image.width, xcf_image.height, + 1, xcf_image.num_colors, + QImage::LittleEndian ); + image.fill( 0 ); + setPalette( xcf_image, image ); + } + + else if ( xcf_image.num_colors <= 256 ) { + image.create( xcf_image.width, xcf_image.height, + 8, xcf_image.num_colors, + QImage::LittleEndian ); + image.fill( 0 ); + setPalette( xcf_image, image ); + } + + break; + + case INDEXEDA_GIMAGE: + + if ( xcf_image.num_colors == 1 ) { + + // Plenty(!) of room to add a transparent color + + xcf_image.num_colors++; + xcf_image.palette.resize( xcf_image.num_colors ); + xcf_image.palette[1] = xcf_image.palette[0]; + xcf_image.palette[0] = qRgba( 255, 255, 255, 0 ); + + image.create( xcf_image.width, xcf_image.height, + 1, xcf_image.num_colors, + QImage::LittleEndian ); + image.fill( 0 ); + setPalette( xcf_image, image ); + image.setAlphaBuffer( true ); + } + + else if ( xcf_image.num_colors < 256 ) { + + // Plenty of room to add a transparent color + + xcf_image.num_colors++; + xcf_image.palette.resize( xcf_image.num_colors ); + for ( int c = xcf_image.num_colors-1; c >= 1; c-- ) + xcf_image.palette[c] = xcf_image.palette[c-1]; + xcf_image.palette[0] = qRgba( 255, 255, 255, 0 ); + + image.create( xcf_image.width, xcf_image.height, + 8, xcf_image.num_colors ); + image.fill( 0 ); + setPalette( xcf_image, image ); + image.setAlphaBuffer( true ); + } + + else { + // No room for a transparent color, so this has to be promoted to + // true color. (There is no equivalent PNG representation output + // from The GIMP as of v1.2.) + image.create( xcf_image.width, xcf_image.height, 32 ); + image.fill( qRgba( 255, 255, 255, 0 ) ); + image.setAlphaBuffer( true ); + } + + break; + } + + image.setDotsPerMeterX( (int)( xcf_image.x_resolution * INCHESPERMETER ) ); + image.setDotsPerMeterY( (int)( xcf_image.y_resolution * INCHESPERMETER ) ); +} + +/*! + * Compute the number of tiles in the current layer and allocate + * QImage structures for each of them. + * \param xcf_image contains the current layer. + */ +void XCFImageFormat::composeTiles ( XCFImage& xcf_image ) +{ + Layer& layer( xcf_image.layer ); + + layer.nrows = ( layer.height + TILE_HEIGHT - 1 ) / TILE_HEIGHT; + layer.ncols = ( layer.width + TILE_WIDTH - 1 ) / TILE_WIDTH; + + layer.image_tiles.resize( layer.nrows ); + + if ( layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE ) + layer.alpha_tiles.resize( layer.nrows ); + + if ( layer.mask_offset != 0 ) + layer.mask_tiles.resize( layer.nrows ); + + for ( uint j = 0; j < layer.nrows; j++ ) { + layer.image_tiles[j].resize( layer.ncols ); + + if ( layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE ) + layer.alpha_tiles[j].resize( layer.ncols ); + + if ( layer.mask_offset != 0 ) + layer.mask_tiles[j].resize( layer.ncols ); + } + + for ( uint j = 0; j < layer.nrows; j++ ) { + for ( uint i = 0; i < layer.ncols; i++ ) { + + uint tile_width = (i+1) * TILE_WIDTH <= layer.width ? + TILE_WIDTH : layer.width - i*TILE_WIDTH; + + uint tile_height = (j+1) * TILE_HEIGHT <= layer.height ? + TILE_HEIGHT : layer.height - j*TILE_HEIGHT; + + // Try to create the most appropriate QImage (each GIMP layer + // type is treated slightly differently) + + switch ( layer.type ) { + case RGB_GIMAGE: + layer.image_tiles[j][i] = QImage( tile_width, tile_height, 32, 0 ); + layer.image_tiles[j][i].setAlphaBuffer( false ); + break; + + case RGBA_GIMAGE: + layer.image_tiles[j][i] = QImage( tile_width, tile_height, 32, 0 ); + layer.image_tiles[j][i].setAlphaBuffer( true ); + break; + + case GRAY_GIMAGE: + layer.image_tiles[j][i] = QImage( tile_width, tile_height, 8, 256 ); + setGrayPalette( layer.image_tiles[j][i] ); + break; + + case GRAYA_GIMAGE: + layer.image_tiles[j][i] = QImage( tile_width, tile_height, 8, 256 ); + setGrayPalette( layer.image_tiles[j][i] ); + + layer.alpha_tiles[j][i] = QImage( tile_width, tile_height, 8, 256 ); + setGrayPalette( layer.alpha_tiles[j][i] ); + break; + + case INDEXED_GIMAGE: + layer.image_tiles[j][i] = QImage( tile_width, tile_height, 8, + xcf_image.num_colors ); + setPalette( xcf_image, layer.image_tiles[j][i] ); + break; + + case INDEXEDA_GIMAGE: + layer.image_tiles[j][i] = QImage( tile_width, tile_height, 8, + xcf_image.num_colors ); + setPalette( xcf_image, layer.image_tiles[j][i] ); + + layer.alpha_tiles[j][i] = QImage( tile_width, tile_height, 8, 256 ); + setGrayPalette( layer.alpha_tiles[j][i] ); + } + + if ( layer.mask_offset != 0 ) { + layer.mask_tiles[j][i] = QImage( tile_width, tile_height, 8, 256 ); + setGrayPalette( layer.mask_tiles[j][i] ); + } + } + } +} + +/*! + * Apply a grayscale palette to the QImage. Note that Qt does not distinguish + * between grayscale and indexed images. A grayscale image is just + * an indexed image with a 256-color, grayscale palette. + * \param image image to set to a grayscale palette. + */ +void XCFImageFormat::setGrayPalette ( QImage& image ) +{ + for ( int i = 0; i < 256; i++ ) + image.setColor( i, qRgb(i,i,i) ); +} + +/*! + * Copy the indexed palette from the XCF image into the QImage. + * \param xcf_image XCF image containing the palette read from the data stream. + * \param image image to apply the palette to. + */ +void XCFImageFormat::setPalette ( XCFImage& xcf_image, QImage& image ) +{ + for ( int i = 0; i < xcf_image.num_colors; i++ ) + image.setColor( i, xcf_image.palette[i] ); +} + +/*! + * An XCF file can contain an arbitrary number of properties associated + * with the image (and layer and mask). + * \param xcf_io the data stream connected to the XCF image + * \param xcf_image XCF image data. + * \return true if there were no I/O errors. + */ +bool XCFImageFormat::loadImageProperties ( SafeDataStream& xcf_io, + XCFImage& xcf_image ) +{ + while ( true ) { + PropType type; + QByteArray bytes; + + if ( !loadProperty( xcf_io, type, bytes ) ) { + qDebug( "XCF: error loading global image properties" ); + return false; + } + + QDataStream property( bytes, IO_ReadOnly ); + + switch ( type ) { + case PROP_END: + return true; + + case PROP_COMPRESSION: + property >> xcf_image.compression; + break; + + case PROP_GUIDES: + // This property is ignored. + break; + + case PROP_RESOLUTION: + property >> xcf_image.x_resolution >> xcf_image.y_resolution; + break; + + case PROP_TATTOO: + property >> xcf_image.tattoo; + break; + + case PROP_PARASITES: + while ( !property.atEnd() ) { + char* tag; + Q_UINT32 size; + + property.readBytes( tag, size ); + + Q_UINT32 flags; + char* data; + property >> flags >> data; + + if ( strcmp( tag, "gimp-comment" ) == 0 ) + xcf_image.image.setText( "Comment", 0, data ); + + delete[] tag; + delete[] data; + } + break; + + case PROP_UNIT: + property >> xcf_image.unit; + break; + + case PROP_PATHS: + // This property is ignored. + break; + + case PROP_USER_UNIT: + // This property is ignored. + break; + + case PROP_COLORMAP: + property >> xcf_image.num_colors; + + xcf_image.palette.reserve( xcf_image.num_colors ); + + for ( int i = 0; i < xcf_image.num_colors; i++ ) { + uchar r, g, b; + property >> r >> g >> b; + xcf_image.palette.push_back( qRgb(r,g,b) ); + } + break; + + default: + qDebug( "XCF: unimplemented image property %d, size %d", type, bytes.size() ); + } + } +} + +/*! + * Load a layer from the XCF file. The data stream must be positioned at + * the beginning of the layer data. + * \param xcf_io the image file data stream. + * \param xcf_image contains the layer and the color table + * (if the image is indexed). + * \return true if there were no I/O errors. + */ +bool XCFImageFormat::loadLayer ( SafeDataStream& xcf_io, XCFImage& xcf_image ) +{ + Layer& layer( xcf_image.layer ); + + if ( layer.name != 0 ) delete[] layer.name; + + xcf_io >> layer.width >> layer.height >> layer.type >> layer.name; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on layer" ); + return false; + } + + if ( !loadLayerProperties( xcf_io, layer ) ) return false; +#if 0 + cout << "layer: \"" << layer.name << "\", size: " << layer.width << " x " + << layer.height << ", type: " << layer.type << ", mode: " << layer.mode + << ", opacity: " << layer.opacity << ", visible: " << layer.visible + << ", offset: " << layer.x_offset << ", " << layer.y_offset << endl; +#endif + // Skip reading the rest of it if it is not visible. Typically, when + // you export an image from the The GIMP it flattens (or merges) only + // the visible layers into the output image. + + if ( layer.visible == 0 ) return true; + + // If there are any more layers, merge them into the final QImage. + + xcf_io >> layer.hierarchy_offset >> layer.mask_offset; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on layer image offsets" ); + return false; + } + + // Allocate the individual tile QImages based on the size and type + // of this layer. + + composeTiles( xcf_image ); + + xcf_io.device()->at( layer.hierarchy_offset ); + + // As tiles are loaded, they are copied into the layers tiles by + // this routine. (loadMask(), below, uses a slightly different + // version of assignBytes().) + + layer.assignBytes = assignImageBytes; + + if ( !loadHierarchy( xcf_io, layer ) ) return false; + + if ( layer.mask_offset != 0 ) { + xcf_io.device()->at( layer.mask_offset ); + + if ( !loadMask( xcf_io, layer ) ) return false; + } + + // Now we should have enough information to initialize the final + // QImage. The first visible layer determines the attributes + // of the QImage. + + if ( !xcf_image.initialized ) { + initializeImage( xcf_image ); + + copyLayerToImage( xcf_image ); + + xcf_image.initialized = true; + } + else + mergeLayerIntoImage( xcf_image ); + + return true; +} + +/*! + * An XCF file can contain an arbitrary number of properties associated + * with a layer. + * \param xcf_io the data stream connected to the XCF image. + * \param layer layer to collect the properties. + * \return true if there were no I/O errors. + */ +bool XCFImageFormat::loadLayerProperties ( SafeDataStream& xcf_io, Layer& layer ) +{ + while ( true ) { + PropType type; + QByteArray bytes; + + if ( !loadProperty( xcf_io, type, bytes ) ) { + qDebug( "XCF: error loading layer properties" ); + return false; + } + + QDataStream property( bytes, IO_ReadOnly ); + + switch ( type ) { + case PROP_END: + return true; + + case PROP_ACTIVE_LAYER: + layer.active = true; + break; + + case PROP_OPACITY: + property >> layer.opacity; + break; + + case PROP_VISIBLE: + property >> layer.visible; + break; + + case PROP_LINKED: + property >> layer.linked; + break; + + case PROP_PRESERVE_TRANSPARENCY: + property >> layer.preserve_transparency; + break; + + case PROP_APPLY_MASK: + property >> layer.apply_mask; + break; + + case PROP_EDIT_MASK: + property >> layer.edit_mask; + break; + + case PROP_SHOW_MASK: + property >> layer.show_mask; + break; + + case PROP_OFFSETS: + property >> layer.x_offset >> layer.y_offset; + break; + + case PROP_MODE: + property >> layer.mode; + break; + + case PROP_TATTOO: + property >> layer.tattoo; + break; + + default: + qDebug( "XCF: unimplemented layer property %d, size %d", type, bytes.size() ); + } + } +} + +/*! + * An XCF file can contain an arbitrary number of properties associated + * with a channel. Note that this routine only reads mask channel properties. + * \param xcf_io the data stream connected to the XCF image. + * \param layer layer containing the mask channel to collect the properties. + * \return true if there were no I/O errors. + */ +bool XCFImageFormat::loadChannelProperties ( SafeDataStream& xcf_io, Layer& layer ) +{ + while ( true ) { + PropType type; + QByteArray bytes; + + if ( !loadProperty( xcf_io, type, bytes ) ) { + qDebug( "XCF: error loading channel properties" ); + return false; + } + + QDataStream property( bytes, IO_ReadOnly ); + + switch ( type ) { + case PROP_END: + return true; + + case PROP_OPACITY: + property >> layer.mask_channel.opacity; + break; + + case PROP_VISIBLE: + property >> layer.mask_channel.visible; + break; + + case PROP_SHOW_MASKED: + property >> layer.mask_channel.show_masked; + break; + + case PROP_COLOR: + property >> layer.mask_channel.red >> layer.mask_channel.green + >> layer.mask_channel.blue; + break; + + case PROP_TATTOO: + property >> layer.mask_channel.tattoo; + break; + + default: + qDebug( "XCF: unimplemented channel property %d, size %d", type, bytes.size() ); + } + } +} + +/*! + * The GIMP stores images in a "mipmap"-like hierarchy. As far as the QImage + * is concerned, however, only the top level (i.e., the full resolution image) + * is used. + * \param xcf_io the data stream connected to the XCF image. + * \param layer the layer to collect the image. + * \return true if there were no I/O errors. + */ +bool XCFImageFormat::loadHierarchy ( SafeDataStream& xcf_io, Layer& layer ) +{ + Q_INT32 width; + Q_INT32 height; + Q_INT32 bpp; + Q_UINT32 offset; + + xcf_io >> width >> height >> bpp >> offset; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on layer %s image header", layer.name ); + return false; + } + + // GIMP stores images in a "mipmap"-like format (multiple levels of + // increasingly lower resolution). Only the top level is used here, + // however. + + Q_UINT32 junk; + do { + xcf_io >> junk; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on layer %s level offsets", layer.name ); + return false; + } + } while ( junk != 0 ); + + QIODevice::Offset saved_pos = xcf_io.device()->at(); + + xcf_io.device()->at( offset ); + + if ( !loadLevel( xcf_io, layer, bpp ) ) return false; + + xcf_io.device()->at( saved_pos ); + + return true; +} + +/*! + * Load one level of the image hierarchy (but only the top level is ever used). + * \param xcf_io the data stream connected to the XCF image. + * \param layer the layer to collect the image. + * \param bpp the number of bytes in a pixel. + * \return true if there were no I/O errors. + * \sa loadTileRLE(). + */ +bool XCFImageFormat::loadLevel ( SafeDataStream& xcf_io, Layer& layer, Q_INT32 bpp ) +{ + Q_INT32 width; + Q_INT32 height; + Q_UINT32 offset; + + xcf_io >> width >> height >> offset; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on layer %s level info", layer.name ); + return false; + } + + if ( offset == 0 ) return true; + + for ( uint j = 0; j < layer.nrows; j++ ) { + for ( uint i = 0; i < layer.ncols; i++ ) { + + if ( offset == 0 ) { + qDebug( "XCF: incorrect number of tiles in layer %s", layer.name ); + return false; + } + + QIODevice::Offset saved_pos = xcf_io.device()->at(); + + Q_UINT32 offset2; + + xcf_io >> offset2; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on layer %s level offset look-ahead", + layer.name ); + return false; + } + + // Evidently, RLE can occasionally expand a tile instead of compressing it! + + if ( offset2 == 0 ) + offset2 = offset + (uint)( TILE_WIDTH * TILE_HEIGHT * 4 * 1.5 ); + + xcf_io.device()->at( offset ); + + int size = layer.image_tiles[j][i].width() * layer.image_tiles[j][i].height(); + + if ( !loadTileRLE( xcf_io, layer.tile, size, offset2 - offset, bpp ) ) + return false; + + // The bytes in the layer tile are juggled differently depending on + // the target QImage. The caller has set layer.assignBytes to the + // appropriate routine. + + layer.assignBytes( layer, i, j ); + + xcf_io.device()->at( saved_pos ); + + xcf_io >> offset; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on layer %s level offset", layer.name ); + return false; + } + } + } + + return true; +} + +/*! + * A layer can have a one channel image which is used as a mask. + * \param xcf_io the data stream connected to the XCF image. + * \param layer the layer to collect the mask image. + * \return true if there were no I/O errors. + */ +bool XCFImageFormat::loadMask ( SafeDataStream& xcf_io, Layer& layer ) +{ + Q_INT32 width; + Q_INT32 height; + char* name; + + xcf_io >> width >> height >> name; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on mask info" ); + return false; + } + + delete name; + + if ( !loadChannelProperties( xcf_io, layer ) ) return false; + + Q_UINT32 hierarchy_offset; + + xcf_io >> hierarchy_offset; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on mask image offset" ); + return false; + } + + xcf_io.device()->at( hierarchy_offset ); + + layer.assignBytes = assignMaskBytes; + + if ( !loadHierarchy( xcf_io, layer ) ) return false; + + return true; +} + +/*! + * This is the routine for which all the other code is simply + * infrastructure. Read the image bytes out of the file and + * store them in the tile buffer. This is passed a full 32-bit deep + * buffer, even if bpp is smaller. The caller can figure out what to + * do with the bytes. + * + * The tile is stored in "channels", i.e. the red component of all + * pixels, then the green component of all pixels, then blue then + * alpha, or, for indexed images, the color indices of all pixels then + * the alpha of all pixels. + * + * The data is compressed with "run length encoding". Some simple data + * integrity checks are made. + * + * \param xcf_io the data stream connected to the XCF image. + * \param tile the buffer to expand the RLE into. + * \param image_size number of bytes expected to be in the image tile. + * \param data_length number of bytes expected in the RLE. + * \param bpp number of bytes per pixel. + * \return true if there were no I/O errors and no obvious corruption of + * the RLE data. + */ +bool XCFImageFormat::loadTileRLE ( SafeDataStream& xcf_io, uchar* tile, int image_size, + int data_length, Q_INT32 bpp ) +{ + uchar* data; + + uchar* xcfdata; + uchar* xcfodata; + uchar* xcfdatalimit; + + xcfdata = xcfodata = new uchar[data_length]; + + int read_length=xcf_io.device()->readBlock( (char*)xcfdata, data_length ); + + if ( read_length<=0 ) { + delete[] xcfodata; + qDebug( "XCF: read failure on tile" ); + return false; + } + + xcfdatalimit = &xcfodata[read_length-1]; + + for ( int i = 0; i < bpp; ++i ) { + + data = tile + i; + + int count = 0; + int size = image_size; + + while ( size > 0 ) { + if ( xcfdata > xcfdatalimit ) + goto bogus_rle; + + uchar val = *xcfdata++; + + uint length = val; + + if ( length >= 128 ) { + length = 255 - ( length - 1 ); + if ( length == 128 ) { + if ( xcfdata >= xcfdatalimit ) + goto bogus_rle; + + length = ( *xcfdata << 8 ) + xcfdata[1]; + + xcfdata += 2; + } + + count += length; + size -= length; + + if ( size < 0 ) + goto bogus_rle; + + if ( &xcfdata[length-1] > xcfdatalimit ) + goto bogus_rle; + + while ( length-- > 0 ) { + *data = *xcfdata++; + data += sizeof(QRgb); + } + } + else { + length += 1; + if ( length == 128 ) { + + if ( xcfdata >= xcfdatalimit ) + goto bogus_rle; + + length = ( *xcfdata << 8 ) + xcfdata[1]; + xcfdata += 2; + } + + count += length; + size -= length; + + if ( size < 0 ) + goto bogus_rle; + + if ( xcfdata > xcfdatalimit ) + goto bogus_rle; + + val = *xcfdata++; + + while ( length-- > 0 ) { + *data = val; + data += sizeof(QRgb); + } + } + } + } + + delete[] xcfodata; + return true; + + bogus_rle: + + qDebug( "The run length encoding could not be decoded properly" ); + delete[] xcfodata; + return false; +} + +/*! + * Copy the bytes from the tile buffer into the image tile QImage, taking into + * account all the myriad different modes. + * \param layer layer containing the tile buffer and the image tile matrix. + * \param i column index of current tile. + * \param j row index of current tile. + */ +void XCFImageFormat::assignImageBytes ( Layer& layer, uint i, uint j ) +{ + uchar* tile = layer.tile; + + switch ( layer.type ) { + case RGB_GIMAGE: + for ( int l = 0; l < layer.image_tiles[j][i].height(); l++ ) { + for ( int k = 0; k < layer.image_tiles[j][i].width(); k++ ) { + layer.image_tiles[j][i].setPixel( k, l, qRgb( tile[0], tile[1], tile[2] ) ); + tile += sizeof(QRgb); + } + } + break; + + case RGBA_GIMAGE: + for ( int l = 0; l < layer.image_tiles[j][i].height(); l++ ) { + for ( int k = 0; k < layer.image_tiles[j][i].width(); k++ ) { + layer.image_tiles[j][i].setPixel( k, l, + qRgba( tile[0], tile[1], tile[2], tile[3] ) ); + tile += sizeof(QRgb); + } + } + break; + + case GRAY_GIMAGE: + case INDEXED_GIMAGE: + for ( int l = 0; l < layer.image_tiles[j][i].height(); l++ ) { + for ( int k = 0; k < layer.image_tiles[j][i].width(); k++ ) { + layer.image_tiles[j][i].setPixel( k, l, tile[0] ); + tile += sizeof(QRgb); + } + } + break; + + case GRAYA_GIMAGE: + case INDEXEDA_GIMAGE: + for ( int l = 0; l < layer.image_tiles[j][i].height(); l++ ) { + for ( int k = 0; k < layer.image_tiles[j][i].width(); k++ ) { + + // The "if" here should not be necessary, but apparently there + // are some cases where the image can contain larger indices + // than there are colors in the palette. (A bug in The GIMP?) + + if ( tile[0] < layer.image_tiles[j][i].numColors() ) + layer.image_tiles[j][i].setPixel( k, l, tile[0] ); + + layer.alpha_tiles[j][i].setPixel( k, l, tile[1] ); + tile += sizeof(QRgb); + } + } + break; + } +} + +/*! + * Copy the bytes from the tile buffer into the mask tile QImage. + * \param layer layer containing the tile buffer and the mask tile matrix. + * \param i column index of current tile. + * \param j row index of current tile. + */ +void XCFImageFormat::assignMaskBytes ( Layer& layer, uint i, uint j ) +{ + uchar* tile = layer.tile; + + for ( int l = 0; l < layer.image_tiles[j][i].height(); l++ ) { + for ( int k = 0; k < layer.image_tiles[j][i].width(); k++ ) { + layer.mask_tiles[j][i].setPixel( k, l, tile[0] ); + tile += sizeof(QRgb); + } + } +} + +/*! + * Read a single property from the image file. The property type is returned + * in type and the data is returned in bytes. + * \param xcf the image file data stream. + * \param type returns with the property type. + * \param bytes returns with the property data. + * \return true if there were no IO errors. */ +bool XCFImageFormat::loadProperty ( SafeDataStream& xcf_io, PropType& type, + QByteArray& bytes ) +{ + Q_UINT32 tmp; + xcf_io >> tmp; + type=static_cast(tmp); + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on property type" ); + return false; + } + + char* data; + Q_UINT32 size; + + // The COLORMAP property is tricky: in version of GIMP older than 2.0.2, the + // property size was wrong (it was 4 + ncolors instead of 4 + 3*ncolors). + // This has been fixed in 2.0.2 (*), but the XCF format version has not been + // increased, so we can't rely on the property size. The UINT32 after the + // property size is the number of colors, which has always been correct, so + // we read it, compute the size from it and put it back in the stream. + // + // * See http://bugzilla.gnome.org/show_bug.cgi?id=142149 and + // gimp/app/xcf-save.c, revision 1.42 + if ( type == PROP_COLORMAP ) { + Q_UINT32 ignoredSize, ncolors; + xcf_io >> ignoredSize; + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on property %d size", type ); + return false; + } + + xcf_io >> ncolors; + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on property %d size", type ); + return false; + } + xcf_io.device()->ungetch( ncolors & 0xff); + xcf_io.device()->ungetch( (ncolors>> 8) & 0xff ); + xcf_io.device()->ungetch( (ncolors>>16) & 0xff ); + xcf_io.device()->ungetch( (ncolors>>24) & 0xff ); + + size=4 + 3 * ncolors; + data = new char[size]; + + xcf_io.readRawBytes( data, size ); + } + + // The USER UNIT property size is not correct. I'm not sure why, though. + + else if ( type == PROP_USER_UNIT ) { + float factor; + Q_INT32 digits; + char* unit_strings; + + xcf_io >> size >> factor >> digits; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on property %d", type ); + return false; + } + + for ( int i = 0; i < 5; i++ ) { + xcf_io >> unit_strings; + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on property %d", type ); + return false; + } + + delete[] unit_strings; + } + + size = 0; + } + + else + xcf_io.readBytes( data, size ); + + if ( xcf_io.failed() ) { + qDebug( "XCF: read failure on property %d data, size %d", type, size ); + return false; + } + + if ( size != 0 ) { + bytes.resize( size ); + + for ( uint i = 0; i < size; i++ ) bytes[i] = data[i]; + + delete[] data; + } + + return true; +} + +/*! + * Copy a layer into an image, taking account of the manifold modes. The + * contents of the image are replaced. + * \param xcf_image contains the layer and image to be replaced. + */ +void XCFImageFormat::copyLayerToImage ( XCFImage& xcf_image ) +{ + Layer& layer( xcf_image.layer ); + QImage& image( xcf_image.image ); + + PixelCopyOperation copy = 0; + + switch ( layer.type ) { + case RGB_GIMAGE: + case RGBA_GIMAGE: + copy = copyRGBToRGB; break; + case GRAY_GIMAGE: + if ( layer.opacity == OPAQUE_OPACITY ) + copy = copyGrayToGray; + else + copy = copyGrayToRGB; + break; + case GRAYA_GIMAGE: + copy = copyGrayAToRGB; break; + case INDEXED_GIMAGE: + copy = copyIndexedToIndexed; break; + case INDEXEDA_GIMAGE: + if ( xcf_image.image.depth() <= 8 ) + copy = copyIndexedAToIndexed; + else + copy = copyIndexedAToRGB; + } + + // For each tile... + + for ( uint j = 0; j < layer.nrows; j++ ) { + uint y = j * TILE_HEIGHT; + + for ( uint i = 0; i < layer.ncols; i++ ) { + uint x = i * TILE_WIDTH; + + // This seems the best place to apply the dissolve because it + // depends on the global position of each tile's + // pixels. Apparently it's the only mode which can apply to a + // single layer. + + if ( layer.mode == DISSOLVE_MODE ) { + if ( layer.type == RGBA_GIMAGE ) + dissolveRGBPixels( layer.image_tiles[j][i], x, y ); + + else if ( layer.type == GRAYA_GIMAGE ) + dissolveAlphaPixels( layer.alpha_tiles[j][i], x, y ); + } + + for ( int l = 0; l < layer.image_tiles[j][i].height(); l++ ) { + for ( int k = 0; k < layer.image_tiles[j][i].width(); k++ ) { + + int m = x + k + layer.x_offset; + int n = y + l + layer.y_offset; + + if ( m < 0 || m >= image.width() || n < 0 || n >= image.height() ) + continue; + + (*copy)( layer, i, j, k, l, image, m, n ); + } + } + } + } +} + +/*! + * Copy an RGB pixel from the layer to the RGB image. Straight-forward. + * The only thing this has to take account of is the opacity of the + * layer. Evidently, the GIMP exporter itself does not actually do this. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::copyRGBToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ) +{ + QRgb src = layer.image_tiles[j][i].pixel( k, l ); + + uchar src_a = layer.opacity; + + if ( layer.type == RGBA_GIMAGE ) + src_a = INT_MULT( src_a, qAlpha( src ) ); + + // Apply the mask (if any) + + if ( layer.apply_mask == 1 && layer.mask_tiles.size() > j && + layer.mask_tiles[j].size() > i ) + src_a = INT_MULT( src_a, layer.mask_tiles[j][i].pixelIndex( k, l ) ); + + image.setPixel( m, n, qRgba( src, src_a ) ); +} + +/*! + * Copy a Gray pixel from the layer to the Gray image. Straight-forward. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::copyGrayToGray ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ) +{ + int src = layer.image_tiles[j][i].pixelIndex( k, l ); + + image.setPixel( m, n, src ); +} + +/*! + * Copy a Gray pixel from the layer to an RGB image. Straight-forward. + * The only thing this has to take account of is the opacity of the + * layer. Evidently, the GIMP exporter itself does not actually do this. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::copyGrayToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ) +{ + QRgb src = layer.image_tiles[j][i].pixel( k, l ); + + uchar src_a = layer.opacity; + + image.setPixel( m, n, qRgba( src, src_a ) ); +} + +/*! + * Copy a GrayA pixel from the layer to an RGB image. Straight-forward. + * The only thing this has to take account of is the opacity of the + * layer. Evidently, the GIMP exporter itself does not actually do this. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::copyGrayAToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ) +{ + QRgb src = layer.image_tiles[j][i].pixel( k, l ); + + uchar src_a = layer.alpha_tiles[j][i].pixelIndex( k, l ); + + src_a = INT_MULT( src_a, layer.opacity ); + + // Apply the mask (if any) + + if ( layer.apply_mask == 1 && layer.mask_tiles.size() > j && + layer.mask_tiles[j].size() > i ) + src_a = INT_MULT( src_a, layer.mask_tiles[j][i].pixelIndex( k, l ) ); + + image.setPixel( m, n, qRgba( src, src_a ) ); +} + +/*! + * Copy an Indexed pixel from the layer to the Indexed image. Straight-forward. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::copyIndexedToIndexed ( Layer& layer, uint i,uint j,int k,int l, + QImage& image, int m, int n ) +{ + int src = layer.image_tiles[j][i].pixelIndex( k, l ); + + image.setPixel( m, n, src ); +} + +/*! + * Copy an IndexedA pixel from the layer to the Indexed image. Straight-forward. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::copyIndexedAToIndexed ( Layer& layer,uint i,uint j,int k,int l, + QImage& image, int m, int n ) +{ + uchar src = layer.image_tiles[j][i].pixelIndex( k, l ); + + uchar src_a = layer.alpha_tiles[j][i].pixelIndex( k, l ); + + src_a = INT_MULT( src_a, layer.opacity ); + + if ( layer.apply_mask == 1 && + layer.mask_tiles.size() > j && + layer.mask_tiles[j].size() > i ) + src_a = INT_MULT( src_a, + layer.mask_tiles[j][i].pixelIndex( k, l ) ); + + if ( src_a > 127 ) + src++; + else + src = 0; + + image.setPixel( m, n, src ); +} + +/*! + * Copy an IndexedA pixel from the layer to an RGB image. Straight-forward. + * The only thing this has to take account of is the opacity of the + * layer. Evidently, the GIMP exporter itself does not actually do this. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::copyIndexedAToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ) +{ + QRgb src = layer.image_tiles[j][i].pixel( k, l ); + + uchar src_a = layer.alpha_tiles[j][i].pixelIndex( k, l ); + + src_a = INT_MULT( src_a, layer.opacity ); + + // Apply the mask (if any) + + if ( layer.apply_mask == 1 && layer.mask_tiles.size() > j && + layer.mask_tiles[j].size() > i ) + src_a = INT_MULT( src_a, layer.mask_tiles[j][i].pixelIndex( k, l ) ); + + // This is what appears in the GIMP window + + if ( src_a <= 127 ) + src_a = 0; + else + src_a = OPAQUE_OPACITY; + + image.setPixel( m, n, qRgba( src, src_a ) ); +} + +/*! + * Merge a layer into an image, taking account of the manifold modes. + * \param xcf_image contains the layer and image to merge. + */ +void XCFImageFormat::mergeLayerIntoImage ( XCFImage& xcf_image ) +{ + Layer& layer( xcf_image.layer ); + QImage& image( xcf_image.image ); + + PixelMergeOperation merge = 0; + + switch ( layer.type ) { + case RGB_GIMAGE: + case RGBA_GIMAGE: + merge = mergeRGBToRGB; break; + case GRAY_GIMAGE: + if ( layer.opacity == OPAQUE_OPACITY ) + merge = mergeGrayToGray; + else + merge = mergeGrayToRGB; + break; + case GRAYA_GIMAGE: + if ( xcf_image.image.depth() <= 8 ) + merge = mergeGrayAToGray; + else + merge = mergeGrayAToRGB; + break; + case INDEXED_GIMAGE: + merge = mergeIndexedToIndexed; break; + case INDEXEDA_GIMAGE: + if ( xcf_image.image.depth() <= 8 ) + merge = mergeIndexedAToIndexed; + else + merge = mergeIndexedAToRGB; + } + + for ( uint j = 0; j < layer.nrows; j++ ) { + uint y = j * TILE_HEIGHT; + + for ( uint i = 0; i < layer.ncols; i++ ) { + uint x = i * TILE_WIDTH; + + // This seems the best place to apply the dissolve because it + // depends on the global position of each tile's + // pixels. Apparently it's the only mode which can apply to a + // single layer. + + if ( layer.mode == DISSOLVE_MODE ) { + if ( layer.type == RGBA_GIMAGE ) + dissolveRGBPixels( layer.image_tiles[j][i], x, y ); + + else if ( layer.type == GRAYA_GIMAGE ) + dissolveAlphaPixels( layer.alpha_tiles[j][i], x, y ); + } + + for ( int l = 0; l < layer.image_tiles[j][i].height(); l++ ) { + for ( int k = 0; k < layer.image_tiles[j][i].width(); k++ ) { + + int m = x + k + layer.x_offset; + int n = y + l + layer.y_offset; + + if ( m < 0 || m >= image.width() || n < 0 || n >= image.height() ) + continue; + + (*merge)( layer, i, j, k, l, image, m, n ); + } + } + } + } +} + +/*! + * Merge an RGB pixel from the layer to the RGB image. Straight-forward. + * The only thing this has to take account of is the opacity of the + * layer. Evidently, the GIMP exporter itself does not actually do this. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::mergeRGBToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ) +{ + QRgb src = layer.image_tiles[j][i].pixel( k, l ); + QRgb dst = image.pixel( m, n ); + + uchar src_r = qRed( src ); + uchar src_g = qGreen( src ); + uchar src_b = qBlue( src ); + uchar src_a = qAlpha( src ); + + uchar dst_r = qRed( dst ); + uchar dst_g = qGreen( dst ); + uchar dst_b = qBlue( dst ); + uchar dst_a = qAlpha( dst ); + + switch ( layer.mode ) { + case MULTIPLY_MODE: { + src_r = INT_MULT( src_r, dst_r ); + src_g = INT_MULT( src_g, dst_g ); + src_b = INT_MULT( src_b, dst_b ); + src_a = MIN( src_a, dst_a ); + } + break; + case DIVIDE_MODE: { + src_r = MIN( ( dst_r * 256 ) / ( 1 + src_r ), 255 ); + src_g = MIN( ( dst_g * 256 ) / ( 1 + src_g ), 255 ); + src_b = MIN( ( dst_b * 256 ) / ( 1 + src_b ), 255 ); + src_a = MIN( src_a, dst_a ); + } + break; + case SCREEN_MODE: { + src_r = 255 - INT_MULT( 255 - dst_r, 255 - src_r ); + src_g = 255 - INT_MULT( 255 - dst_g, 255 - src_g ); + src_b = 255 - INT_MULT( 255 - dst_b, 255 - src_b ); + src_a = MIN( src_a, dst_a ); + } + break; + case OVERLAY_MODE: { + src_r = INT_MULT( dst_r, dst_r + INT_MULT( 2 * src_r, 255 - dst_r ) ); + src_g = INT_MULT( dst_g, dst_g + INT_MULT( 2 * src_g, 255 - dst_g ) ); + src_b = INT_MULT( dst_b, dst_b + INT_MULT( 2 * src_b, 255 - dst_b ) ); + src_a = MIN( src_a, dst_a ); + } + break; + case DIFFERENCE_MODE: { + src_r = dst_r > src_r ? dst_r - src_r : src_r - dst_r; + src_g = dst_g > src_g ? dst_g - src_g : src_g - dst_g; + src_b = dst_b > src_b ? dst_b - src_b : src_b - dst_b; + src_a = MIN( src_a, dst_a ); + } + break; + case ADDITION_MODE: { + src_r = add_lut[dst_r][src_r]; + src_g = add_lut[dst_g][src_g]; + src_b = add_lut[dst_b][src_b]; + src_a = MIN( src_a, dst_a ); + } + break; + case SUBTRACT_MODE: { + src_r = dst_r > src_r ? dst_r - src_r : 0; + src_g = dst_g > src_g ? dst_g - src_g : 0; + src_b = dst_b > src_b ? dst_b - src_b : 0; + src_a = MIN( src_a, dst_a ); + } + break; + case DARKEN_ONLY_MODE: { + src_r = dst_r < src_r ? dst_r : src_r; + src_g = dst_g < src_g ? dst_g : src_g; + src_b = dst_b < src_b ? dst_b : src_b; + src_a = MIN( src_a, dst_a ); + } + break; + case LIGHTEN_ONLY_MODE: { + src_r = dst_r < src_r ? src_r : dst_r; + src_g = dst_g < src_g ? src_g : dst_g; + src_b = dst_b < src_b ? src_b : dst_b; + src_a = MIN( src_a, dst_a ); + } + break; + case HUE_MODE: { + uchar new_r = dst_r; + uchar new_g = dst_g; + uchar new_b = dst_b; + + RGBTOHSV( src_r, src_g, src_b ); + RGBTOHSV( new_r, new_g, new_b ); + + new_r = src_r; + + HSVTORGB( new_r, new_g, new_b ); + + src_r = new_r; + src_g = new_g; + src_b = new_b; + src_a = MIN( src_a, dst_a ); + } + break; + case SATURATION_MODE: { + uchar new_r = dst_r; + uchar new_g = dst_g; + uchar new_b = dst_b; + + RGBTOHSV( src_r, src_g, src_b ); + RGBTOHSV( new_r, new_g, new_b ); + + new_g = src_g; + + HSVTORGB( new_r, new_g, new_b ); + + src_r = new_r; + src_g = new_g; + src_b = new_b; + src_a = MIN( src_a, dst_a ); + } + break; + case VALUE_MODE: { + uchar new_r = dst_r; + uchar new_g = dst_g; + uchar new_b = dst_b; + + RGBTOHSV( src_r, src_g, src_b ); + RGBTOHSV( new_r, new_g, new_b ); + + new_b = src_b; + + HSVTORGB( new_r, new_g, new_b ); + + src_r = new_r; + src_g = new_g; + src_b = new_b; + src_a = MIN( src_a, dst_a ); + } + break; + case COLOR_MODE: { + uchar new_r = dst_r; + uchar new_g = dst_g; + uchar new_b = dst_b; + + RGBTOHLS( src_r, src_g, src_b ); + RGBTOHLS( new_r, new_g, new_b ); + + new_r = src_r; + new_b = src_b; + + HLSTORGB( new_r, new_g, new_b ); + + src_r = new_r; + src_g = new_g; + src_b = new_b; + src_a = MIN( src_a, dst_a ); + } + break; + } + + src_a = INT_MULT( src_a, layer.opacity ); + + // Apply the mask (if any) + + if ( layer.apply_mask == 1 && layer.mask_tiles.size() > j && + layer.mask_tiles[j].size() > i ) + src_a = INT_MULT( src_a, layer.mask_tiles[j][i].pixelIndex( k, l ) ); + + uchar new_r, new_g, new_b, new_a; + + new_a = dst_a + INT_MULT( OPAQUE_OPACITY - dst_a, src_a ); + + float src_ratio = (float)src_a / new_a; + float dst_ratio = 1. - src_ratio; + + new_r = (uchar)( src_ratio * src_r + dst_ratio * dst_r + EPSILON ); + new_g = (uchar)( src_ratio * src_g + dst_ratio * dst_g + EPSILON ); + new_b = (uchar)( src_ratio * src_b + dst_ratio * dst_b + EPSILON ); + + if ( !layer_modes[layer.mode].affect_alpha ) + new_a = dst_a; + + image.setPixel( m, n, qRgba( new_r, new_g, new_b, new_a ) ); +} + +/*! + * Merge a Gray pixel from the layer to the Gray image. Straight-forward. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::mergeGrayToGray ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ) +{ + int src = layer.image_tiles[j][i].pixelIndex( k, l ); + + image.setPixel( m, n, src ); +} + +/*! + * Merge a GrayA pixel from the layer to the Gray image. Straight-forward. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::mergeGrayAToGray ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ) +{ + int src = qGray( layer.image_tiles[j][i].pixel( k, l ) ); + int dst = image.pixelIndex( m, n ); + + uchar src_a = layer.alpha_tiles[j][i].pixelIndex( k, l ); + + switch ( layer.mode ) { + case MULTIPLY_MODE: { + src = INT_MULT( src, dst ); + } + break; + case DIVIDE_MODE: { + src = MIN( ( dst * 256 ) / ( 1 + src ), 255 ); + } + break; + case SCREEN_MODE: { + src = 255 - INT_MULT( 255 - dst, 255 - src ); + } + break; + case OVERLAY_MODE: { + src = INT_MULT( dst, dst + INT_MULT( 2 * src, 255 - dst ) ); + } + break; + case DIFFERENCE_MODE: { + src = dst > src ? dst - src : src - dst; + } + break; + case ADDITION_MODE: { + src = add_lut[dst][src]; + } + break; + case SUBTRACT_MODE: { + src = dst > src ? dst - src : 0; + } + break; + case DARKEN_ONLY_MODE: { + src = dst < src ? dst : src; + } + break; + case LIGHTEN_ONLY_MODE: { + src = dst < src ? src : dst; + } + break; + } + + src_a = INT_MULT( src_a, layer.opacity ); + + // Apply the mask (if any) + + if ( layer.apply_mask == 1 && layer.mask_tiles.size() > j && + layer.mask_tiles[j].size() > i ) + src_a = INT_MULT( src_a, layer.mask_tiles[j][i].pixelIndex( k, l ) ); + + uchar new_a = OPAQUE_OPACITY; + + float src_ratio = (float)src_a / new_a; + float dst_ratio = 1. - src_ratio; + + uchar new_g = (uchar)( src_ratio * src + dst_ratio * dst + EPSILON ); + + image.setPixel( m, n, new_g ); +} + +/*! + * Merge a Gray pixel from the layer to an RGB image. Straight-forward. + * The only thing this has to take account of is the opacity of the + * layer. Evidently, the GIMP exporter itself does not actually do this. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::mergeGrayToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ) +{ + QRgb src = layer.image_tiles[j][i].pixel( k, l ); + + uchar src_a = layer.opacity; + + image.setPixel( m, n, qRgba( src, src_a ) ); +} + +/*! + * Merge a GrayA pixel from the layer to an RGB image. Straight-forward. + * The only thing this has to take account of is the opacity of the + * layer. Evidently, the GIMP exporter itself does not actually do this. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::mergeGrayAToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ) +{ + int src = qGray( layer.image_tiles[j][i].pixel( k, l ) ); + int dst = qGray( image.pixel( m, n ) ); + + uchar src_a = layer.alpha_tiles[j][i].pixelIndex( k, l ); + uchar dst_a = qAlpha( image.pixel( m, n ) ); + + switch ( layer.mode ) { + case MULTIPLY_MODE: { + src = INT_MULT( src, dst ); + src_a = MIN( src_a, dst_a ); + } + break; + case DIVIDE_MODE: { + src = MIN( ( dst * 256 ) / ( 1 + src ), 255 ); + src_a = MIN( src_a, dst_a ); + } + break; + case SCREEN_MODE: { + src = 255 - INT_MULT( 255 - dst, 255 - src ); + src_a = MIN( src_a, dst_a ); + } + break; + case OVERLAY_MODE: { + src = INT_MULT( dst, dst + INT_MULT( 2 * src, 255 - dst ) ); + src_a = MIN( src_a, dst_a ); + } + break; + case DIFFERENCE_MODE: { + src = dst > src ? dst - src : src - dst; + src_a = MIN( src_a, dst_a ); + } + break; + case ADDITION_MODE: { + src = add_lut[dst][src]; + src_a = MIN( src_a, dst_a ); + } + break; + case SUBTRACT_MODE: { + src = dst > src ? dst - src : 0; + src_a = MIN( src_a, dst_a ); + } + break; + case DARKEN_ONLY_MODE: { + src = dst < src ? dst : src; + src_a = MIN( src_a, dst_a ); + } + break; + case LIGHTEN_ONLY_MODE: { + src = dst < src ? src : dst; + src_a = MIN( src_a, dst_a ); + } + break; + } + + src_a = INT_MULT( src_a, layer.opacity ); + + // Apply the mask (if any) + + if ( layer.apply_mask == 1 && layer.mask_tiles.size() > j && + layer.mask_tiles[j].size() > i ) + src_a = INT_MULT( src_a, layer.mask_tiles[j][i].pixelIndex( k, l ) ); + + uchar new_a = dst_a + INT_MULT( OPAQUE_OPACITY - dst_a, src_a ); + + float src_ratio = (float)src_a / new_a; + float dst_ratio = 1. - src_ratio; + + uchar new_g = (uchar)( src_ratio * src + dst_ratio * dst + EPSILON ); + + if ( !layer_modes[layer.mode].affect_alpha ) + new_a = dst_a; + + image.setPixel( m, n, qRgba( new_g, new_g, new_g, new_a ) ); +} + +/*! + * Merge an Indexed pixel from the layer to the Indexed image. Straight-forward. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::mergeIndexedToIndexed ( Layer& layer, uint i,uint j,int k,int l, + QImage& image, int m, int n ) +{ + int src = layer.image_tiles[j][i].pixelIndex( k, l ); + + image.setPixel( m, n, src ); +} + +/*! + * Merge an IndexedA pixel from the layer to the Indexed image. Straight-forward. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::mergeIndexedAToIndexed ( Layer& layer,uint i,uint j,int k,int l, + QImage& image, int m, int n ) +{ + uchar src = layer.image_tiles[j][i].pixelIndex( k, l ); + + uchar src_a = layer.alpha_tiles[j][i].pixelIndex( k, l ); + + src_a = INT_MULT( src_a, layer.opacity ); + + if ( layer.apply_mask == 1 && + layer.mask_tiles.size() > j && + layer.mask_tiles[j].size() > i ) + src_a = INT_MULT( src_a, + layer.mask_tiles[j][i].pixelIndex( k, l ) ); + + if ( src_a > 127 ) { + src++; + image.setPixel( m, n, src ); + } +} + +/*! + * Merge an IndexedA pixel from the layer to an RGB image. Straight-forward. + * The only thing this has to take account of is the opacity of the + * layer. Evidently, the GIMP exporter itself does not actually do this. + * \param layer source layer. + * \param i x tile index. + * \param j y tile index. + * \param k x pixel index of tile i,j. + * \param l y pixel index of tile i,j. + * \param image destination image. + * \param m x pixel of destination image. + * \param n y pixel of destination image. + */ +void XCFImageFormat::mergeIndexedAToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ) +{ + QRgb src = layer.image_tiles[j][i].pixel( k, l ); + + uchar src_a = layer.alpha_tiles[j][i].pixelIndex( k, l ); + + src_a = INT_MULT( src_a, layer.opacity ); + + // Apply the mask (if any) + + if ( layer.apply_mask == 1 && layer.mask_tiles.size() > j && + layer.mask_tiles[j].size() > i ) + src_a = INT_MULT( src_a, layer.mask_tiles[j][i].pixelIndex( k, l ) ); + + // This is what appears in the GIMP window + + if ( src_a <= 127 ) + src_a = 0; + else + src_a = OPAQUE_OPACITY; + + image.setPixel( m, n, qRgba( src, src_a ) ); +} + +/*! + * Dissolving pixels: pick a random number between 0 and 255. If the pixel's + * alpha is less than that, make it transparent. + * \param image the image tile to dissolve. + * \param x the global x position of the tile. + * \param y the global y position of the tile. + */ +void XCFImageFormat::dissolveRGBPixels ( QImage& image, int x, int y ) +{ + // The apparently spurious rand() calls are to wind the random + // numbers up to the same point for each tile. + + for ( int l = 0; l < image.height(); l++ ) { + srand( random_table[( l + y ) % RANDOM_TABLE_SIZE] ); + + for ( int k = 0; k < x; k++ ) + rand(); + + for ( int k = 0; k < image.width(); k++ ) { + int rand_val = rand() & 0xff; + QRgb pixel = image.pixel( k, l ); + + if ( rand_val > qAlpha( pixel ) ) { + image.setPixel( k, l, qRgba( pixel, 0 ) ); + } + } + } +} + +/*! + * Dissolving pixels: pick a random number between 0 and 255. If the pixel's + * alpha is less than that, make it transparent. This routine works for + * the GRAYA and INDEXEDA image types where the pixel alpha's are stored + * separately from the pixel themselves. + * \param image the alpha tile to dissolve. + * \param x the global x position of the tile. + * \param y the global y position of the tile. + */ +void XCFImageFormat::dissolveAlphaPixels ( QImage& image, int x, int y ) +{ + // The apparently spurious rand() calls are to wind the random + // numbers up to the same point for each tile. + + for ( int l = 0; l < image.height(); l++ ) { + srand( random_table[( l + y ) % RANDOM_TABLE_SIZE] ); + + for ( int k = 0; k < x; k++ ) + rand(); + + for ( int k = 0; k < image.width(); k++ ) { + int rand_val = rand() & 0xff; + uchar alpha = image.pixelIndex( k, l ); + + if ( rand_val > alpha ) { + image.setPixel( k, l, 0 ); + } + } + } +} + +KDE_Q_EXPORT_PLUGIN( XCFImageFormat ) + +} // namespace diff --git a/src/gvcore/qxcfi.h b/src/gvcore/qxcfi.h new file mode 100644 index 0000000..ac82173 --- /dev/null +++ b/src/gvcore/qxcfi.h @@ -0,0 +1,332 @@ +#ifndef QXCFI_H +#define QXCFI_H + +#include +#include +#include +#include + +#include "gimp.h" +namespace Gwenview { + +// Safe readBlock helper functions +class SafeDataStream { +public: + SafeDataStream(QIODevice* device) + : mDevice(device), mFailed(false) {} + + bool failed() const { return mFailed; } + QIODevice* device() const { return mDevice; } + + SafeDataStream& readRawBytes(char* data, uint length) { + if (mFailed) return *this; + int read_length=mDevice->readBlock(data, length); + if (read_length==-1) mFailed=true; + if ((uint)read_length!=length) mFailed=true; + return *this; + } + + SafeDataStream& operator>>(Q_INT8& value) { + return readRawBytes((char*)&value, 1); + } + + SafeDataStream& operator>>(Q_UINT32& value) { + if (mFailed) return *this; + uchar *p = (uchar *)(&value); + char b[4]; + if (mDevice->readBlock( b, 4 )==4) { + *p++ = b[3]; + *p++ = b[2]; + *p++ = b[1]; + *p = b[0]; + } else { + mFailed=true; + } + return *this; + } + + SafeDataStream& operator>>(Q_INT32& value) { + return *this >>((Q_UINT32&)value); + } + + SafeDataStream& operator>>(float& value) { + return *this >>((Q_UINT32&)value); + } + + SafeDataStream& operator>>(char*& value) { + if (mFailed) return *this; + + Q_UINT32 len; + *this >> len; + if (mFailed) return *this; + if ( len == 0 ) { + value = 0; + return *this; + } + if (mDevice->atEnd() ) { + value = 0; + mFailed=true; + return *this; + } + value = new char[len]; + Q_CHECK_PTR( value ); + if ( !value ) { + mFailed=true; + return *this; + } + return readRawBytes(value, len); + } + + SafeDataStream& readBytes(char*& data, uint& len) { + if (mFailed) return *this; + + *this >> len; + if (mFailed) return *this; + data=new char[len]; + Q_CHECK_PTR( data ); + if ( !data ) { + mFailed=true; + return *this; + } + return readRawBytes(data, len); + } + + // This method is usefull to debug with gdb. Do not inline it! + int at() const; + +private: + QIODevice* mDevice; + bool mFailed; +}; + +//! Plug-in for loading a GIMP XCF image file directly. +/*! + * This class uses the Qt 3.0 Image format plug-in loader to provide + * the ability to read The GIMP XCF image files. This plug-in will + * be dynamically loaded as needed. + */ +class XCFImageFormat : public QImageFormatPlugin { + + /*! + * Each layer in an XCF file is stored as a matrix of + * 64-pixel by 64-pixel images. The GIMP has a sophisticated + * method of handling very large images as well as implementing + * parallel processing on a tile-by-tile basis. Here, though, + * we just read them in en-masse and store them in a matrix. + */ + typedef QValueVector< QValueVector< QImage > > Tiles; + + /*! + * Each GIMP image is composed of one or more layers. A layer can + * be one of any three basic types: RGB, grayscale or indexed. With an + * optional alpha channel, there are six possible types altogether. + * + * Note: there is only ever one instance of this structure. The + * layer info is discarded after it is merged into the final QImage. + */ + struct Layer { + Q_UINT32 width; //!< Width of the layer + Q_UINT32 height; //!< Height of the layer + Q_INT32 type; //!< Type of the layer (GimpImageType) + char* name; //!< Name of the layer + Q_UINT32 hierarchy_offset; //!< File position of Tile hierarchy + Q_UINT32 mask_offset; //!< File position of mask image + + uint nrows; //!< Number of rows of tiles (y direction) + uint ncols; //!< Number of columns of tiles (x direction) + + Tiles image_tiles; //!< The basic image + //! For Grayscale and Indexed images, the alpha channel is stored + //! separately (in this data structure, anyway). + Tiles alpha_tiles; + Tiles mask_tiles; //!< The layer mask (optional) + + //! Additional information about a layer mask. + struct { + Q_UINT32 opacity; + Q_UINT32 visible; + Q_UINT32 show_masked; + uchar red, green, blue; + Q_UINT32 tattoo; + } mask_channel; + + bool active; //!< Is this layer the active layer? + Q_UINT32 opacity; //!< The opacity of the layer + Q_UINT32 visible; //!< Is the layer visible? + Q_UINT32 linked; //!< Is this layer linked (geometrically) + Q_UINT32 preserve_transparency; //!< Preserve alpha when drawing on layer? + Q_UINT32 apply_mask; //!< Apply the layer mask? + Q_UINT32 edit_mask; //!< Is the layer mask the being edited? + Q_UINT32 show_mask; //!< Show the layer mask rather than the image? + Q_INT32 x_offset; //!< x offset of the layer relative to the image + Q_INT32 y_offset; //!< y offset of the layer relative to the image + Q_UINT32 mode; //!< Combining mode of layer (LayerModeEffects) + Q_UINT32 tattoo; //!< (unique identifier?) + + //! As each tile is read from the file, it is buffered here. + uchar tile[TILE_WIDTH * TILE_HEIGHT * sizeof(QRgb)]; + + //! The data from tile buffer is copied to the Tile by this + //! method. Depending on the type of the tile (RGB, Grayscale, + //! Indexed) and use (image or mask), the bytes in the buffer are + //! copied in different ways. + void (*assignBytes)( Layer& layer, uint i, uint j ); + + //! Construct a layer. + Layer ( void ) : name( 0 ) {} + //! Destruct the layer. + ~Layer ( void ) { if ( name != 0 ) delete[] name; } + }; + + /*! + * The in-memory representation of the XCF Image. It contains a few + * metadata items, but is mostly a container for the layer information. + */ + struct XCFImage { + Q_UINT32 width; //!< width of the XCF image + Q_UINT32 height; //!< height of the XCF image + Q_INT32 type; //!< type of the XCF image (GimpImageBaseType) + + Q_UINT8 compression; //!< tile compression method (CompressionType) + float x_resolution; //!< x resolution in dots per inch + float y_resolution; //!< y resolution in dots per inch + Q_INT32 tattoo; //!< (unique identifier?) + Q_UINT32 unit; //!< Units of The GIMP (inch, mm, pica, etc...) + Q_INT32 num_colors; //!< number of colors in an indexed image + QValueVector< QRgb > palette; //!< indexed image color palette + + int num_layers; //!< number of layers + Layer layer; //!< most recently read layer + + bool initialized; //!< Is the QImage initialized? + QImage image; //!< final QImage + + //! Simple constructor. + XCFImage ( void ) : initialized( false ) {} + }; + + //! The bottom-most layer is copied into the final QImage by this + //! routine. + typedef void (*PixelCopyOperation) ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + + //! Higher layers are merged into the the final QImage by this routine. + typedef void (*PixelMergeOperation) ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + + //! In layer DISSOLVE mode, a random number is chosen to compare to a + //! pixel's alpha. If the alpha is greater than the random number, the + //! pixel is drawn. This table merely contains the random number seeds + //! for each ROW of an image. Therefore, the random numbers chosen + //! are consistent from run to run. + + static int random_table[RANDOM_TABLE_SIZE]; + + //! This table provides the add_pixel saturation values (i.e. 250 + 250 = 255). + + static int add_lut[256][256]; + + //! Layer mode static data. + typedef struct { + bool affect_alpha; //!< Does this mode affect the source alpha? + } LayerModes; + + //! Array of layer mode structures for the modes described by + //! LayerModeEffects. + static LayerModes layer_modes[]; + +public: + /*! + * The constructor for the XCF image loader. This initializes the + * tables used in the layer merging routines. + */ + XCFImageFormat (); + + + /*! + * The image loader makes no (direct) use of dynamic memory + * and the Qt infrastructure takes care of constructing and destructing + * the loader so there is not much to do here. + */ + ~XCFImageFormat () {} + + /*! + * You can query Qt about the types of image file formats it knows about + * via QImage::inputFormats or QImage::inputFormatList(). + * This method returns "xcf". + */ + QStringList keys () const { + return QStringList() << "XCF"; + } + + /*! + * This method installs the XCF reader on demand. + */ + bool installIOHandler ( const QString& ); + + static void registerFormat(); + +private: + static void readXCF ( QImageIO* image_io ); +#ifdef TMP_WRITE + static void writeXCF ( QImageIO* ) {} +#endif + static void initializeImage ( XCFImage& xcf_image ); + static void composeTiles ( XCFImage& xcf_image ); + static bool loadImageProperties ( SafeDataStream& xcf_io, XCFImage& image ); + static bool loadLayer ( SafeDataStream& xcf_io, XCFImage& xcf_image ); + static bool loadLayerProperties ( SafeDataStream& xcf_io, Layer& layer ); + static bool loadChannelProperties ( SafeDataStream& xcf_io, Layer& layer ); + static bool loadHierarchy ( SafeDataStream& xcf_io, Layer& layer ); + static bool loadMask ( SafeDataStream& xcf_io, Layer& layer ); + static bool loadLevel ( SafeDataStream& xcf_io, Layer& layer, Q_INT32 bpp ); + static bool loadTileRLE ( SafeDataStream& xcf_io, uchar* tile, int size, + int data_length, Q_INT32 bpp ); + static bool loadProperty ( SafeDataStream& xcf_io, PropType& type, + QByteArray& bytes ); + static void setGrayPalette ( QImage& image ); + static void setPalette ( XCFImage& xcf_image, QImage& image ); + static void assignImageBytes ( Layer& layer, uint i, uint j ); + static void assignMaskBytes ( Layer& layer, uint i, uint j ); + + static void copyLayerToImage ( XCFImage& xcf_image ); + static void copyRGBToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void copyGrayToGray ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void copyGrayToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void copyGrayAToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void copyIndexedToIndexed ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void copyIndexedAToIndexed ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void copyIndexedAToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + + static void mergeLayerIntoImage ( XCFImage& xcf_image ); + static void mergeRGBToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void mergeGrayToGray ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void mergeGrayAToGray ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void mergeGrayToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void mergeGrayAToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void mergeIndexedToIndexed ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void mergeIndexedAToIndexed ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + static void mergeIndexedAToRGB ( Layer& layer, uint i, uint j, int k, int l, + QImage& image, int m, int n ); + + static void dissolveRGBPixels ( QImage& image, int x, int y ); + static void dissolveAlphaPixels ( QImage& image, int x, int y ); +}; + +} // namespace +#endif + diff --git a/src/gvcore/slideshow.cpp b/src/gvcore/slideshow.cpp new file mode 100644 index 0000000..fb9442a --- /dev/null +++ b/src/gvcore/slideshow.cpp @@ -0,0 +1,217 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +// kate: indent-mode csands; indent-width 4; replace-tabs-save off; replace-tabs off; replace-trailing-space-save off; space-indent off; tabs-indents on; tab-width 4; +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// STL +#include + +// Qt +#include + +// KDE +#include +#include + +// Local +#include <../gvcore/slideshowconfig.h> +#include "slideshow.moc" + +#include "document.h" +#include "imageloader.h" +#include "cache.h" + +namespace Gwenview { + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + +SlideShow::SlideShow(Document* document) +: mDocument(document), mStarted(false), mPrefetch( NULL ) { + mTimer=new QTimer(this); + connect(mTimer, SIGNAL(timeout()), + this, SLOT(slotTimeout()) ); + connect(mDocument, SIGNAL(loaded(const KURL&)), + this, SLOT(slotLoaded()) ); +} + +SlideShow::~SlideShow() { + if( !mPriorityURL.isEmpty()) Cache::instance()->setPriorityURL( mPriorityURL, false ); +} + + +void SlideShow::slotSettingsChanged() { + if (mTimer->isActive()) { + mTimer->changeInterval(timerInterval()); + } +} + + +int SlideShow::timerInterval() { + int documentDuration = mDocument->duration(); + if (documentDuration != 0) { + return documentDuration * 1000; + } else { + return int(SlideShowConfig::delay()*1000); + } +} + + +void SlideShow::start(const KURL::List& urls) { + mURLs.resize(urls.size()); + qCopy(urls.begin(), urls.end(), mURLs.begin()); + if (SlideShowConfig::random()) { + std::random_shuffle(mURLs.begin(), mURLs.end()); + } + + mStartIt=qFind(mURLs.begin(), mURLs.end(), mDocument->url()); + if (mStartIt==mURLs.end()) { + kdWarning() << k_funcinfo << "Current URL not found in list, aborting.\n"; + return; + } + + mTimer->start(timerInterval(), true); + mStarted=true; + prefetch(); + emit stateChanged(true); +} + + +void SlideShow::stop() { + mTimer->stop(); + mStarted=false; + emit stateChanged(false); + if( !mPriorityURL.isEmpty()) { + Cache::instance()->setPriorityURL( mPriorityURL, false ); + mPriorityURL = KURL(); + } +} + + +QValueVector::ConstIterator SlideShow::findNextURL() const { + QValueVector::ConstIterator it=qFind(mURLs.begin(), mURLs.end(), mDocument->url()); + if (it==mURLs.end()) { + kdWarning() << k_funcinfo << "Current URL not found in list. This should not happen.\n"; + return it; + } + + ++it; + if (SlideShowConfig::loop()) { + // Looping, if we reach the end, start again + if (it==mURLs.end()) { + it = mURLs.begin(); + } + } else { + // Not looping, have we reached the end? + if ((it==mURLs.end() && SlideShowConfig::stopAtEnd()) || it==mStartIt) { + it = mURLs.end(); + } + } + + return it; +} + + +void SlideShow::slotTimeout() { + LOG(""); + // wait for prefetching to finish + if( mPrefetch != NULL ) { + LOG("mPrefetch is working"); + return; + } + + QValueVector::ConstIterator it=findNextURL(); + if (it==mURLs.end()) { + stop(); + return; + } + emit nextURL(*it); +} + + +void SlideShow::slotLoaded() { + if (mStarted) { + mTimer->start(timerInterval(), true); + prefetch(); + } +} + + +void SlideShow::prefetch() { + LOG(""); + QValueVector::ConstIterator it=findNextURL(); + if (it==mURLs.end()) { + return; + } + LOG("url=" << (*it).pathOrURL()); + + if( mPrefetch != NULL ) mPrefetch->release( this ); + // TODO don't use prefetching with disabled optimizations (and add that option ;) ) + // (and also don't use prefetching in other places if the image won't fit in cache) + mPrefetch = ImageLoader::loader( *it, this, BUSY_PRELOADING ); + if( !mPriorityURL.isEmpty()) Cache::instance()->setPriorityURL( mPriorityURL, false ); + mPriorityURL = *it; + Cache::instance()->setPriorityURL( mPriorityURL, true ); // make sure it will stay in the cache + connect( mPrefetch, SIGNAL( urlKindDetermined()), SLOT( slotUrlKindDetermined())); + connect( mPrefetch, SIGNAL( imageLoaded( bool )), SLOT( prefetchDone())); + + if (mPrefetch->urlKind()==MimeTypeUtils::KIND_FILE) { + // Prefetch is already done, and this is not a raster image + prefetchDone(); + } +} + +void SlideShow::slotUrlKindDetermined() { + LOG(""); + if (!mPrefetch) return; + + LOG("mPrefetch!=0"); + if (mPrefetch->urlKind()==MimeTypeUtils::KIND_FILE) { + LOG("KIND_FILE"); + // This is not a raster image, imageLoaded will not be emitted + prefetchDone(); + } +} + + +void SlideShow::prefetchDone() { + LOG(""); + if( mPrefetch != NULL ) { + LOG("mPrefetch!=0"); + // don't call Cache::setPriorityURL( ... , false ) here - it will still take + // a short while to reuse the image from the cache + mPrefetch->release( this ); + mPrefetch = NULL; + // prefetching completed and delay has already elapsed + if( mStarted && !mTimer->isActive()) { + LOG("Calling slotTimeout"); + slotTimeout(); + } + } +} + + +} // namespace diff --git a/src/gvcore/slideshow.h b/src/gvcore/slideshow.h new file mode 100644 index 0000000..fcb1d1a --- /dev/null +++ b/src/gvcore/slideshow.h @@ -0,0 +1,86 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +// kate: indent-mode csands; indent-width 4; replace-tabs-save off; replace-tabs off; replace-trailing-space-save off; space-indent off; tabs-indents on; tab-width 4; +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aur�ien G�eau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef SLIDESHOW_H +#define SLIDESHOW_H + +// Qt +#include +#include + +// KDE +#include +#include "libgwenview_export.h" +class QTimer; + +class KConfig; + +namespace Gwenview { +class Document; +class ImageLoader; + +class LIBGWENVIEW_EXPORT SlideShow : public QObject +{ +Q_OBJECT +public: + SlideShow(Document* document); + virtual ~SlideShow(); + + void start(const KURL::List& urls); + void stop(); + + /** @return true if the slideshow is running */ + bool isRunning() { return mStarted; } + +public slots: + void slotSettingsChanged(); + +signals: + void nextURL( const KURL& ); + /** + * Slideshow has been started or stopped + */ + void stateChanged(bool running); + +private slots: + void slotTimeout(); + void slotLoaded(); + void slotUrlKindDetermined(); + void prefetchDone(); + +private: + QValueVector::ConstIterator findNextURL() const; + void prefetch(); + int timerInterval(); + + QTimer* mTimer; + Document* mDocument; + bool mStarted; + QValueVector mURLs; + QValueVector::ConstIterator mStartIt; + ImageLoader* mPrefetch; + KURL mPriorityURL; +}; + +} // namespace +#endif // SLIDESHOW_H + diff --git a/src/gvcore/slideshowconfig.kcfg b/src/gvcore/slideshowconfig.kcfg new file mode 100644 index 0000000..9f110d9 --- /dev/null +++ b/src/gvcore/slideshowconfig.kcfg @@ -0,0 +1,27 @@ + + + + + + + + false + + + + true + + + + false + + + + false + + + + 10.0 + + + diff --git a/src/gvcore/slideshowconfig.kcfgc b/src/gvcore/slideshowconfig.kcfgc new file mode 100644 index 0000000..85b2ff8 --- /dev/null +++ b/src/gvcore/slideshowconfig.kcfgc @@ -0,0 +1,7 @@ +File=slideshowconfig.kcfg +ClassName=SlideShowConfig +NameSpace=Gwenview +Singleton=true +Mutators=true +IncludeFiles=gvcore/libgwenview_export.h +Visibility=LIBGWENVIEW_EXPORT diff --git a/src/gvcore/threadgate.cpp b/src/gvcore/threadgate.cpp new file mode 100644 index 0000000..3d09b9f --- /dev/null +++ b/src/gvcore/threadgate.cpp @@ -0,0 +1,60 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "threadgate.moc" + +#include "tsthread/tsthread.h" + +namespace Gwenview { + +// The trick is simple. This object connects its slot to its signal, then +// emits the signal using emitSignal(), and the slot gets called in the main +// thread. In the main thread the slot does everything that should be done +// in the main thread, and returns the data using the signal/slot reference +// arguments. As the thread is blocked waiting on the signal to finish, +// there's even no need to do any locking. + +ThreadGate::ThreadGate() { + connect( this, SIGNAL( signalColor( QColor&, const char* )), + this, SLOT( slotColor( QColor&, const char* ))); +} + +ThreadGate* ThreadGate::instance() { + static ThreadGate gate; + return &gate; +} + +QColor ThreadGate::color( const char* name ) { + if( name == NULL || name[ 0 ] == '\0' || name[ 0 ] == '#' ) + return QColor( name ); + // named color ... needs to be created in the main thread + if( TSThread::currentThread() == TSThread::mainThread()) + return QColor( name ); + QColor col; + TSThread::currentThread()->emitCancellableSignal( this, SIGNAL( signalColor( QColor&, const char* )), col, name ); + return col; +} + +void ThreadGate::slotColor( QColor& col, const char* name ) { + col = QColor( name ); +} + +} // namespace diff --git a/src/gvcore/threadgate.h b/src/gvcore/threadgate.h new file mode 100644 index 0000000..4783198 --- /dev/null +++ b/src/gvcore/threadgate.h @@ -0,0 +1,45 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef THREADGATE_H +#define THREADGATE_H + +#include +#include +namespace Gwenview { + +class ThreadGate : public QObject +{ +Q_OBJECT +public: + static ThreadGate* instance(); + QColor color( const char* name ); +private: + ThreadGate(); +signals: + void signalColor( QColor&, const char* ); +private slots: + void slotColor( QColor&, const char* ); +}; + +} // namespace +#endif + diff --git a/src/gvcore/thumbnaildetailsdialog.cpp b/src/gvcore/thumbnaildetailsdialog.cpp new file mode 100644 index 0000000..ed514ed --- /dev/null +++ b/src/gvcore/thumbnaildetailsdialog.cpp @@ -0,0 +1,78 @@ +// vi: tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2005 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "thumbnaildetailsdialog.moc" + +// Qt +#include + +// Local +#include "filethumbnailview.h" +#include "thumbnaildetailsdialogbase.h" + + +namespace Gwenview { + +struct ThumbnailDetailsDialog::Private { + FileThumbnailView* mView; + ThumbnailDetailsDialogBase* mContent; +}; + +ThumbnailDetailsDialog::ThumbnailDetailsDialog(FileThumbnailView* view) +: KDialogBase( + view, 0, false /* modal */, QString::null, KDialogBase::Close, + KDialogBase::Close, true /* separator */) +, d(new ThumbnailDetailsDialog::Private) +{ + d->mView=view; + d->mContent=new ThumbnailDetailsDialogBase(this); + setMainWidget(d->mContent); + setCaption(d->mContent->caption()); + + int details=d->mView->itemDetails(); + d->mContent->mShowFileName->setChecked(details & FileThumbnailView::FILENAME); + d->mContent->mShowFileDate->setChecked(details & FileThumbnailView::FILEDATE); + d->mContent->mShowFileSize->setChecked(details & FileThumbnailView::FILESIZE); + d->mContent->mShowImageSize->setChecked(details & FileThumbnailView::IMAGESIZE); + + connect(d->mContent->mShowFileName, SIGNAL(toggled(bool)), SLOT(applyChanges()) ); + connect(d->mContent->mShowFileDate, SIGNAL(toggled(bool)), SLOT(applyChanges()) ); + connect(d->mContent->mShowFileSize, SIGNAL(toggled(bool)), SLOT(applyChanges()) ); + connect(d->mContent->mShowImageSize, SIGNAL(toggled(bool)), SLOT(applyChanges()) ); +} + +ThumbnailDetailsDialog::~ThumbnailDetailsDialog() { + delete d; +} + + +void ThumbnailDetailsDialog::applyChanges() { + int details= + (d->mContent->mShowFileName->isChecked() ? FileThumbnailView::FILENAME : 0) + | (d->mContent->mShowFileDate->isChecked() ? FileThumbnailView::FILEDATE : 0) + | (d->mContent->mShowFileSize->isChecked() ? FileThumbnailView::FILESIZE : 0) + | (d->mContent->mShowImageSize->isChecked() ? FileThumbnailView::IMAGESIZE : 0) + ; + d->mView->setItemDetails(details); +} + + +} // namespace diff --git a/src/gvcore/thumbnaildetailsdialog.h b/src/gvcore/thumbnaildetailsdialog.h new file mode 100644 index 0000000..9706c20 --- /dev/null +++ b/src/gvcore/thumbnaildetailsdialog.h @@ -0,0 +1,47 @@ +// vi: tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2005 Aurelien Gateau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef THUMBNAILDETAILSDIALOG_H +#define THUMBNAILDETAILSDIALOG_H + +// KDE +#include + +namespace Gwenview { + +class FileThumbnailView; + +class ThumbnailDetailsDialog : public KDialogBase { +Q_OBJECT +public: + ThumbnailDetailsDialog(FileThumbnailView* view); + ~ThumbnailDetailsDialog(); + +private slots: + void applyChanges(); + +private: + struct Private; + Private* d; +}; + +} // namespace + +#endif /* THUMBNAILDETAILSDIALOG_H */ diff --git a/src/gvcore/thumbnaildetailsdialogbase.ui b/src/gvcore/thumbnaildetailsdialogbase.ui new file mode 100644 index 0000000..4057968 --- /dev/null +++ b/src/gvcore/thumbnaildetailsdialogbase.ui @@ -0,0 +1,117 @@ + +ThumbnailDetailsDialogBase + + + ThumbnailDetailsDialogBase + + + + 0 + 0 + 390 + 207 + + + + Thumbnail Details + + + + unnamed + + + + textLabel1 + + + Information to display in the thumbnail text: + + + + + layout6 + + + + unnamed + + + + spacer7 + + + Horizontal + + + Fixed + + + + 21 + 20 + + + + + + mShowFileName + + + File name + + + + + mShowImageSize + + + Image size + + + + + mShowFileSize + + + File size + + + + + mShowFileDate + + + File date + + + + + + + spacer7_2 + + + Vertical + + + Fixed + + + + 21 + 21 + + + + + + textLabel1_2 + + + <i>For more options, use the "Configure Gwenview" dialog</i> + + + + + + diff --git a/src/gvcore/thumbnailloadjob.cpp b/src/gvcore/thumbnailloadjob.cpp new file mode 100644 index 0000000..92290ac --- /dev/null +++ b/src/gvcore/thumbnailloadjob.cpp @@ -0,0 +1,763 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* Gwenview - A simple image viewer for KDE + Copyright 2000-2004 Aurlien Gteau + This class is based on the ImagePreviewJob class from Konqueror. + Original copyright follows. +*/ +/* This file is part of the KDE project + Copyright (C) 2000 David Faure + 2000 Carsten Pfeiffer + + This program is free software; you can redistribute it and/or modify + it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "thumbnailloadjob.moc" + +#include +#include +#include +#include + +// Qt +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// libjpeg +#include +#define XMD_H +extern "C" { +#include +} + +// Local +#include "cache.h" +#include "mimetypeutils.h" +#include "miscconfig.h" +#include "imageutils/jpegcontent.h" +#include "imageutils/imageutils.h" +#include "thumbnailsize.h" +#include "fileviewconfig.h" +namespace Gwenview { + +#undef ENABLE_LOG +#undef LOG +//#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + + +static QString generateOriginalURI(KURL url) { + // Don't include the password if any + url.setPass(QString::null); + return url.url(); +} + + +static QString generateThumbnailPath(const QString& uri, int size) { + KMD5 md5( QFile::encodeName(uri) ); + QString baseDir=ThumbnailLoadJob::thumbnailBaseDir(size); + return baseDir + QString(QFile::encodeName( md5.hexDigest())) + ".png"; +} + +//------------------------------------------------------------------------ +// +// ThumbnailThread +// +//------------------------------------------------------------------------ +void ThumbnailThread::load( + const QString& originalURI, time_t originalTime, int originalSize, const QString& originalMimeType, + const QString& pixPath, + const QString& thumbnailPath, + int size, bool storeThumbnail) +{ + QMutexLocker lock( &mMutex ); + assert( mPixPath.isNull()); + + mOriginalURI = TSDeepCopy(originalURI); + mOriginalTime = originalTime; + mOriginalSize = originalSize; + mOriginalMimeType = TSDeepCopy(originalMimeType); + mPixPath = TSDeepCopy(pixPath); + mThumbnailPath = TSDeepCopy(thumbnailPath); + mThumbnailSize = size; + mStoreThumbnailsInCache = storeThumbnail; + if(!running()) start(); + mCond.wakeOne(); +} + +void ThumbnailThread::run() { + QMutexLocker lock( &mMutex ); + while( !testCancel()) { + // empty mPixPath means nothing to do + while( mPixPath.isNull()) { + mCond.cancellableWait( &mMutex ); + if( testCancel()) return; + } + loadThumbnail(); + mPixPath = QString(); // done, ready for next + QSize size(mOriginalWidth, mOriginalHeight); + emitCancellableSignal( this, SIGNAL( done( const QImage&, const QSize&)), mImage, size); + } +} + +void ThumbnailThread::loadThumbnail() { + mImage = QImage(); + bool loaded=false; + bool needCaching=true; + + // If it's a JPEG, try to load a small image directly from the file + if (isJPEG()) { + ImageUtils::JPEGContent content; + content.load(mPixPath); + mOriginalWidth = content.size().width(); + mOriginalHeight = content.size().height(); + mImage = content.thumbnail(); + + if( !mImage.isNull() + && ( mImage.width() >= mThumbnailSize // don't use small thumbnails + || mImage.height() >= mThumbnailSize )) { + loaded = true; + needCaching = false; + } + if(!loaded) { + loaded=loadJPEG(); + } + if (loaded && MiscConfig::autoRotateImages()) { + // Rotate if necessary + ImageUtils::Orientation orientation = content.orientation(); + mImage=ImageUtils::transform(mImage,orientation); + } + } + // File is not a JPEG, or JPEG optimized load failed, load file using Qt + if (!loaded) { + QImage originalImage; + if (originalImage.load(mPixPath)) { + mOriginalWidth=originalImage.width(); + mOriginalHeight=originalImage.height(); + int thumbSize=mThumbnailSize<=ThumbnailSize::NORMAL ? ThumbnailSize::NORMAL : ThumbnailSize::LARGE; + + if( testCancel()) return; + + if (QMAX(mOriginalWidth, mOriginalHeight)<=thumbSize ) { + mImage=originalImage; + needCaching = false; + } else { + mImage=ImageUtils::scale(originalImage,thumbSize,thumbSize,ImageUtils::SMOOTH_FAST,QImage::ScaleMin); + } + loaded = true; + } + } + + if( testCancel()) return; + + if( mStoreThumbnailsInCache && needCaching ) { + mImage.setText("Thumb::URI", 0, mOriginalURI); + mImage.setText("Thumb::MTime", 0, QString::number(mOriginalTime)); + mImage.setText("Thumb::Size", 0, QString::number(mOriginalSize)); + mImage.setText("Thumb::Mimetype", 0, mOriginalMimeType); + mImage.setText("Thumb::Image::Width", 0, QString::number(mOriginalWidth)); + mImage.setText("Thumb::Image::Height", 0, QString::number(mOriginalHeight)); + mImage.setText("Software", 0, "Gwenview"); + + QString thumbnailDir = ThumbnailLoadJob::thumbnailBaseDir(mThumbnailSize); + KStandardDirs::makeDir(thumbnailDir, 0700); + + KTempFile tmp(thumbnailDir + "/gwenview", ".png"); + tmp.setAutoDelete(true); + if (tmp.status()!=0) { + QString reason( strerror(tmp.status()) ); + kdWarning() << "Could not create a temporary file.\nReason: " << reason << endl; + return; + } + + if (!mImage.save(tmp.name(), "PNG")) { + kdWarning() << "Could not save thumbnail for file " << mOriginalURI << endl; + return; + } + + rename(QFile::encodeName(tmp.name()), QFile::encodeName(mThumbnailPath)); + } +} + + +bool ThumbnailThread::isJPEG() { + QString format=QImageIO::imageFormat(mPixPath); + return format=="JPEG"; +} + + + +struct JPEGFatalError : public jpeg_error_mgr { + jmp_buf mJmpBuffer; + + static void handler(j_common_ptr cinfo) { + JPEGFatalError* error=static_cast(cinfo->err); + (error->output_message)(cinfo); + longjmp(error->mJmpBuffer,1); + } +}; + +bool ThumbnailThread::loadJPEG() { + struct jpeg_decompress_struct cinfo; + + // Open file + FILE* inputFile=fopen(QFile::encodeName( mPixPath ).data(), "rb"); + if(!inputFile) return false; + + // Error handling + struct JPEGFatalError jerr; + cinfo.err = jpeg_std_error(&jerr); + cinfo.err->error_exit = JPEGFatalError::handler; + if (setjmp(jerr.mJmpBuffer)) { + jpeg_destroy_decompress(&cinfo); + fclose(inputFile); + return false; + } + + // Init decompression + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, inputFile); + jpeg_read_header(&cinfo, TRUE); + + // Get image size and check if we need a thumbnail + int size= mThumbnailSize <= ThumbnailSize::NORMAL ? ThumbnailSize::NORMAL : ThumbnailSize::LARGE; + int imgSize = QMAX(cinfo.image_width, cinfo.image_height); + + if (imgSize<=size) { + fclose(inputFile); + return mImage.load(mPixPath); + } + + // Compute scale value + int scale=1; + while(size*scale*2<=imgSize) { + scale*=2; + } + if(scale>8) scale=8; + + cinfo.scale_num=1; + cinfo.scale_denom=scale; + + // Create QImage + jpeg_start_decompress(&cinfo); + + switch(cinfo.output_components) { + case 3: + case 4: + mImage.create( cinfo.output_width, cinfo.output_height, 32 ); + break; + case 1: // B&W image + mImage.create( cinfo.output_width, cinfo.output_height, 8, 256 ); + for (int i=0; i<256; i++) + mImage.setColor(i, qRgb(i,i,i)); + break; + default: + jpeg_destroy_decompress(&cinfo); + fclose(inputFile); + return false; + } + + uchar** lines = mImage.jumpTable(); + while (cinfo.output_scanline < cinfo.output_height) { + jpeg_read_scanlines(&cinfo, lines + cinfo.output_scanline, cinfo.output_height); + } + jpeg_finish_decompress(&cinfo); + +// Expand 24->32 bpp + if ( cinfo.output_components == 3 ) { + for (uint j=0; j* items, int size) +: KIO::Job(false), mState( STATE_NEXTTHUMB ), + mCurrentVisibleIndex( -1 ), mFirstVisibleIndex( -1 ), mLastVisibleIndex( -1 ), + mThumbnailSize(size), mSuspended( false ) +{ + LOG(""); + + mBrokenPixmap=KGlobal::iconLoader()->loadIcon("file_broken", + KIcon::NoGroup, ThumbnailSize::MIN); + + // Look for images and store the items in our todo list + Q_ASSERT(!items->empty()); + mAllItems=*items; + mProcessedState.resize( mAllItems.count()); + qFill( mProcessedState.begin(), mProcessedState.end(), false ); + mCurrentItem = NULL; + + connect(&mThumbnailThread, SIGNAL(done(const QImage&, const QSize&)), + SLOT(thumbnailReady(const QImage&, const QSize&)) ); + Cache::instance()->updateAge(); // see addThumbnail in Cache +} + + +ThumbnailLoadJob::~ThumbnailLoadJob() { + LOG(""); + mThumbnailThread.cancel(); + mThumbnailThread.wait(); +} + + +void ThumbnailLoadJob::start() { + // build mItems from mAllItems if not done yet + if (mLastVisibleIndex == -1 ) { + setPriorityItems( NULL, NULL, NULL ); + } + if (mItems.isEmpty()) { + LOG("Nothing to do"); + emit result(this); + delete this; + return; + } + + determineNextIcon(); +} + +void ThumbnailLoadJob::suspend() { + mSuspended = true; +} + +void ThumbnailLoadJob::resume() { + if( !mSuspended ) return; + mSuspended = false; + if( mState == STATE_NEXTTHUMB ) // don't load next while already loading + determineNextIcon(); +} + +//-Internal-------------------------------------------------------------- +void ThumbnailLoadJob::appendItem(const KFileItem* item) { + int index = thumbnailIndex( item ); + if( index >= 0 ) { + mProcessedState[ index ] = false; + return; + } + mAllItems.append(item); + mProcessedState.append( false ); + updateItemsOrder(); +} + + +void ThumbnailLoadJob::itemRemoved(const KFileItem* item) { + Q_ASSERT(item); + + // If we are removing the next item, update to be the item after or the + // first if we removed the last item + mItems.remove( item ); + int index = thumbnailIndex( item ); + if( index >= 0 ) { + mAllItems.erase( mAllItems.begin() + index ); + mProcessedState.erase( mProcessedState.begin() + index ); + } + + if (item == mCurrentItem) { + // Abort + mCurrentItem = NULL; + if (subjobs.first()) { + subjobs.first()->kill(); + subjobs.removeFirst(); + } + determineNextIcon(); + } +} + + +void ThumbnailLoadJob::setPriorityItems(const KFileItem* current, const KFileItem* first, const KFileItem* last) { + if( mAllItems.isEmpty()) { + mCurrentVisibleIndex = mFirstVisibleIndex = mLastVisibleIndex = 0; + return; + } + mFirstVisibleIndex = -1; + mLastVisibleIndex = - 1; + mCurrentVisibleIndex = -1; + if( first != NULL ) mFirstVisibleIndex = thumbnailIndex( first ); + if( last != NULL ) mLastVisibleIndex = thumbnailIndex( last ); + if( current != NULL ) mCurrentVisibleIndex = thumbnailIndex( current ); + if( mFirstVisibleIndex == -1 ) mFirstVisibleIndex = 0; + if( mLastVisibleIndex == -1 ) mLastVisibleIndex = mAllItems.count() - 1; + if( mCurrentVisibleIndex == -1 ) mCurrentVisibleIndex = mFirstVisibleIndex; + updateItemsOrder(); +} + +void ThumbnailLoadJob::updateItemsOrder() { + mItems.clear(); + int forward = mCurrentVisibleIndex + 1; + int backward = mCurrentVisibleIndex; + int first = mFirstVisibleIndex; + int last = mLastVisibleIndex; + updateItemsOrderHelper( forward, backward, first, last ); + if( first != 0 || last != int( mAllItems.count()) - 1 ) { + // add non-visible items + updateItemsOrderHelper( last + 1, first - 1, 0, mAllItems.count() - 1); + } +} + +void ThumbnailLoadJob::updateItemsOrderHelper( int forward, int backward, int first, int last ) { + // start from the current item, add one following it, and one preceding it, for all visible items + while( forward <= last || backward >= first ) { + // start with backward - that's the curent item for the first time + while( backward >= first ) { + if( !mProcessedState[ backward ] ) { + mItems.append( mAllItems[ backward ] ); + --backward; + break; + } + --backward; + } + while( forward <= last ) { + if( !mProcessedState[ forward ] ) { + mItems.append( mAllItems[ forward ] ); + ++forward; + break; + } + ++forward; + } + } +} + +void ThumbnailLoadJob::determineNextIcon() { + mState = STATE_NEXTTHUMB; + if( mSuspended ) { + return; + } + + // No more items ? + if (mItems.isEmpty()) { + // Done + LOG("emitting result"); + emit result(this); + delete this; + return; + } + + mCurrentItem=mItems.first(); + mItems.pop_front(); + Q_ASSERT( !mProcessedState[ thumbnailIndex( mCurrentItem )] ); + mProcessedState[ thumbnailIndex( mCurrentItem )] = true; + + // First, stat the orig file + mState = STATE_STATORIG; + mOriginalTime = 0; + mCurrentURL = mCurrentItem->url(); + mCurrentURL.cleanPath(); + + // Do direct stat instead of using KIO if the file is local (faster) + if( mCurrentURL.isLocalFile() + && !KIO::probably_slow_mounted( mCurrentURL.path())) { + KDE_struct_stat buff; + if ( KDE_stat( QFile::encodeName(mCurrentURL.path()), &buff ) == 0 ) { + mOriginalTime = buff.st_mtime; + QTimer::singleShot( 0, this, SLOT( checkThumbnail())); + } + } + if( mOriginalTime == 0 ) { // KIO must be used + KIO::Job* job = KIO::stat(mCurrentURL,false); + job->setWindow(KApplication::kApplication()->mainWidget()); + LOG( "KIO::stat orig " << mCurrentURL.url() ); + addSubjob(job); + } +} + + +void ThumbnailLoadJob::slotResult(KIO::Job * job) { + LOG(mState); + subjobs.remove(job); + Q_ASSERT(subjobs.isEmpty()); // We should have only one job at a time ... + + switch (mState) { + case STATE_NEXTTHUMB: + Q_ASSERT(false); + determineNextIcon(); + return; + + case STATE_STATORIG: { + // Could not stat original, drop this one and move on to the next one + if (job->error()) { + emitThumbnailLoadingFailed(); + determineNextIcon(); + return; + } + + // Get modification time of the original file + KIO::UDSEntry entry = static_cast(job)->statResult(); + KIO::UDSEntry::ConstIterator it= entry.begin(); + mOriginalTime = 0; + for (; it!=entry.end(); ++it) { + if ((*it).m_uds == KIO::UDS_MODIFICATION_TIME) { + mOriginalTime = (time_t)((*it).m_long); + break; + } + } + checkThumbnail(); + return; + } + + case STATE_DOWNLOADORIG: + if (job->error()) { + emitThumbnailLoadingFailed(); + LOG("Delete temp file " << mTempPath); + QFile::remove(mTempPath); + mTempPath = QString::null; + determineNextIcon(); + } else { + startCreatingThumbnail(mTempPath); + } + return; + + case STATE_PREVIEWJOB: + determineNextIcon(); + return; + } +} + + +void ThumbnailLoadJob::thumbnailReady( const QImage& im, const QSize& _size) { + QImage img = TSDeepCopy( im ); + QSize size = _size; + if ( !img.isNull()) { + emitThumbnailLoaded(img, size); + } else { + emitThumbnailLoadingFailed(); + } + if( !mTempPath.isEmpty()) { + LOG("Delete temp file " << mTempPath); + QFile::remove(mTempPath); + mTempPath = QString::null; + } + determineNextIcon(); +} + +void ThumbnailLoadJob::checkThumbnail() { + // If we are in the thumbnail dir, just load the file + if (mCurrentURL.isLocalFile() + && mCurrentURL.directory(false).startsWith(thumbnailBaseDir()) ) + { + QImage image(mCurrentURL.path()); + emitThumbnailLoaded(image, image.size()); + determineNextIcon(); + return; + } + QSize imagesize; + if( mOriginalTime == time_t( Cache::instance()->timestamp( mCurrentURL ).toTime_t())) { + QPixmap cached = Cache::instance()->thumbnail( mCurrentURL, imagesize ); + if( !cached.isNull()) { + emit thumbnailLoaded(mCurrentItem, cached, imagesize); + determineNextIcon(); + return; + } + } + + mOriginalURI=generateOriginalURI(mCurrentURL); + mThumbnailPath=generateThumbnailPath(mOriginalURI, mThumbnailSize); + + LOG("Stat thumb " << mThumbnailPath); + + QImage thumb; + if ( thumb.load(mThumbnailPath) ) { + if (thumb.text("Thumb::URI", 0) == mOriginalURI && + thumb.text("Thumb::MTime", 0).toInt() == mOriginalTime ) + { + int width=0, height=0; + QSize size; + bool ok; + + width=thumb.text("Thumb::Image::Width", 0).toInt(&ok); + if (ok) height=thumb.text("Thumb::Image::Height", 0).toInt(&ok); + if (ok) { + size=QSize(width, height); + } else { + LOG("Thumbnail for " << mOriginalURI << " does not contain correct image size information"); + KFileMetaInfo fmi(mCurrentURL); + if (fmi.isValid()) { + KFileMetaInfoItem item=fmi.item("Dimensions"); + if (item.isValid()) { + size=item.value().toSize(); + } else { + LOG("KFileMetaInfoItem for " << mOriginalURI << " did not get image size information"); + } + } else { + LOG("Could not get a valid KFileMetaInfo instance for " << mOriginalURI); + } + } + emitThumbnailLoaded(thumb, size); + determineNextIcon(); + return; + } + } + + // Thumbnail not found or not valid + if ( MimeTypeUtils::rasterImageMimeTypes().contains(mCurrentItem->mimetype()) ) { + // This is a raster image + if (mCurrentURL.isLocalFile()) { + // Original is a local file, create the thumbnail + startCreatingThumbnail(mCurrentURL.path()); + } else { + // Original is remote, download it + mState=STATE_DOWNLOADORIG; + KTempFile tmpFile; + mTempPath=tmpFile.name(); + KURL url; + url.setPath(mTempPath); + KIO::Job* job=KIO::file_copy(mCurrentURL, url,-1,true,false,false); + job->setWindow(KApplication::kApplication()->mainWidget()); + LOG("Download remote file " << mCurrentURL.prettyURL()); + addSubjob(job); + } + } else { + // Not a raster image, use a KPreviewJob + mState=STATE_PREVIEWJOB; + KFileItemList list; + list.append(mCurrentItem); + KIO::Job* job=KIO::filePreview(list, mThumbnailSize); + job->setWindow(KApplication::kApplication()->mainWidget()); + connect(job, SIGNAL(gotPreview(const KFileItem*, const QPixmap&)), + this, SLOT(slotGotPreview(const KFileItem*, const QPixmap&)) ); + connect(job, SIGNAL(failed(const KFileItem*)), + this, SLOT(emitThumbnailLoadingFailed()) ); + addSubjob(job); + return; + } +} + +void ThumbnailLoadJob::startCreatingThumbnail(const QString& pixPath) { + LOG("Creating thumbnail from " << pixPath); + mThumbnailThread.load( mOriginalURI, mOriginalTime, mCurrentItem->size(), + mCurrentItem->mimetype(), pixPath, mThumbnailPath, mThumbnailSize, + FileViewConfig::storeThumbnailsInCache()); +} + + +void ThumbnailLoadJob::slotGotPreview(const KFileItem* item, const QPixmap& pixmap) { + LOG(""); + QSize size; + emit thumbnailLoaded(item, pixmap, size); +} + + +void ThumbnailLoadJob::emitThumbnailLoaded(const QImage& img, QSize size) { + int biggestDimension=QMAX(img.width(), img.height()); + + QImage thumbImg; + if (biggestDimension>mThumbnailSize) { + // Scale down thumbnail if necessary + thumbImg=ImageUtils::scale(img,mThumbnailSize, mThumbnailSize, ImageUtils::SMOOTH_FAST,QImage::ScaleMin); + } else { + thumbImg=img; + } + QDateTime tm; + tm.setTime_t( mOriginalTime ); + QPixmap thumb( thumbImg ); // store as QPixmap in cache (faster to retrieve, no conversion needed) + Cache::instance()->addThumbnail( mCurrentURL, thumb, size, tm ); + emit thumbnailLoaded(mCurrentItem, thumb, size); +} + + +void ThumbnailLoadJob::emitThumbnailLoadingFailed() { + QSize size; + emit thumbnailLoaded(mCurrentItem, mBrokenPixmap, size); +} + + +} // namespace diff --git a/src/gvcore/thumbnailloadjob.h b/src/gvcore/thumbnailloadjob.h new file mode 100644 index 0000000..331708d --- /dev/null +++ b/src/gvcore/thumbnailloadjob.h @@ -0,0 +1,211 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* Gwenview - A simple image viewer for KDE + Copyright 2000-2004 Aurlien Gteau + This class is based on the ImagePreviewJob class from Konqueror. + Original copyright follows. +*/ +/* This file is part of the KDE project + Copyright (C) 2000 David Faure + + This program is free software; you can redistribute it and/or modify + it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef THUMBNAILLOADJOB_H +#define THUMBNAILLOADJOB_H + +// Qt +#include +#include +#include +#include + +// KDE +#include + +// Local +#include "tsthread/tsthread.h" +#include "tsthread/tswaitcondition.h" + +#include "libgwenview_export.h" +class KConfig; +class KFileItem; + +typedef QPtrList KFileItemList; + +namespace Gwenview { +class ThumbnailThread : public TSThread { +Q_OBJECT +public: + void load( + const QString& originalURI, + time_t originalTime, + int originalSize, + const QString& originalMimeType, + const QString& pixPath, + const QString& thumbnailPath, + int size, + bool storeThumbnail); +protected: + virtual void run(); +signals: + void done( const QImage&, const QSize&); +private: + bool isJPEG(); + bool loadJPEG(); + void loadThumbnail(); + QImage mImage; + QString mPixPath; + QString mThumbnailPath; + QString mOriginalURI; + time_t mOriginalTime; + int mOriginalSize; + QString mOriginalMimeType; + int mOriginalWidth; + int mOriginalHeight; + QMutex mMutex; + TSWaitCondition mCond; + int mThumbnailSize; + bool mStoreThumbnailsInCache; +}; + +/** + * A job that determines the thumbnails for the images in the current directory + */ +class LIBGWENVIEW_EXPORT ThumbnailLoadJob : public KIO::Job { +Q_OBJECT +public: + /** + * Create a job for determining the pixmaps of the images in the @p itemList + */ + ThumbnailLoadJob(const QValueVector* itemList, int size); + virtual ~ThumbnailLoadJob(); + + /** + * Call this to get started + */ + void start(); + + /** + * To be called whenever an item is removed from the view + */ + void itemRemoved(const KFileItem* item); + + + /** + * Add an item to a running job + */ + void appendItem(const KFileItem* item); + + + /** + * Sets items in range first..last to be generated first, starting with current. + */ + void setPriorityItems(const KFileItem* current, const KFileItem* first, const KFileItem* last); + + /** + * Temporarily suspends loading. Used if there's a more + * important action going on (loading an image etc.). + */ + void suspend(); + + /** + * Resumes loading if suspended. + */ + void resume(); + + /** + * Returns the thumbnail base dir, independent of the thumbnail size + */ + static QString thumbnailBaseDir(); + + /** + * Returns the thumbnail base dir, for the @p size + */ + static QString thumbnailBaseDir(int size); + + + /** + * Delete the thumbnail for the @p url + */ + static void deleteImageThumbnail(const KURL& url); + +signals: + /** + * Emitted when the thumbnail for the @p item has been loaded + */ + void thumbnailLoaded(const KFileItem* item, const QPixmap&, const QSize&); + +private slots: + void slotResult( KIO::Job *job ); + void slotGotPreview(const KFileItem*, const QPixmap&); + void checkThumbnail(); + void thumbnailReady(const QImage& im, const QSize&); + void emitThumbnailLoadingFailed(); + +private: + enum { STATE_STATORIG, STATE_DOWNLOADORIG, STATE_PREVIEWJOB, STATE_NEXTTHUMB } mState; + + QValueList mItems; + QValueVector mAllItems; + QValueVector< bool > mProcessedState; + const KFileItem *mCurrentItem; + int thumbnailIndex( const KFileItem* item ) const; + void updateItemsOrder(); + + // indexes of the current, fist and last visible thumbnails + int mCurrentVisibleIndex, mFirstVisibleIndex, mLastVisibleIndex; + + // The URL of the current item (always equivalent to m_items.first()->item()->url()) + KURL mCurrentURL; + + // The URI of the original image (might be different from mCurrentURL.url()) + QString mOriginalURI; + + // The modification time of the original image + time_t mOriginalTime; + + // The thumbnail path + QString mThumbnailPath; + + // The temporary path for remote urls + QString mTempPath; + + // Thumbnail size + int mThumbnailSize; + + QPixmap mBrokenPixmap; + + bool mSuspended; + + ThumbnailThread mThumbnailThread; + + void determineNextIcon(); + void startCreatingThumbnail(const QString& path); + + void emitThumbnailLoaded(const QImage& img, QSize size); + + void updateItemsOrderHelper( int forward, int backward, int first, int last ); +}; + +inline +int ThumbnailLoadJob::thumbnailIndex( const KFileItem* item ) const { + QValueVector::ConstIterator pos = qFind( mAllItems.begin(), mAllItems.end(), item ); + if( pos != mAllItems.end()) return pos - mAllItems.begin(); + return -1; +} + +} // namespace +#endif + diff --git a/src/gvcore/thumbnailsize.h b/src/gvcore/thumbnailsize.h new file mode 100644 index 0000000..400c22e --- /dev/null +++ b/src/gvcore/thumbnailsize.h @@ -0,0 +1,42 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* Gwenview - A simple image viewer for KDE + Copyright 2000-2004 Aurlien Gteau + This class is based on the ImagePreviewJob class from Konqueror. + Original copyright follows. +*/ +/* This file is part of the KDE project + Copyright (C) 2000 David Faure + 2000 Carsten Pfeiffer + + This program is free software; you can redistribute it and/or modify + it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifndef THUMBNAILSIZE_H +#define THUMBNAILSIZE_H + +namespace Gwenview { + +/** + * This namespace stores constants used by several files. It avoids multiple + * includes. + */ +namespace ThumbnailSize { + const int MIN=48; + const int NORMAL=128; + const int LARGE=256; +} + +} // namespace +#endif /* THUMBNAILSIZE_H */ + diff --git a/src/gvcore/timeutils.cpp b/src/gvcore/timeutils.cpp new file mode 100644 index 0000000..d79c24d --- /dev/null +++ b/src/gvcore/timeutils.cpp @@ -0,0 +1,53 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2006 Aurélien Gâteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "timeutils.h" + +// KDE +#include +#include +#include +#include +#include + +namespace Gwenview { +namespace TimeUtils { + +time_t getTime(const KFileItem* item) { + const KFileMetaInfo& info = item->metaInfo(); + if (info.isValid()) { + QVariant value = info.value("Date/time"); + QDateTime dt = value.toDateTime(); + if (dt.isValid()) { + return dt.toTime_t(); + } + } + return item->time(KIO::UDS_MODIFICATION_TIME); +} + +QString formatTime(time_t time) { + QDateTime dt; + dt.setTime_t(time); + return KGlobal::locale()->formatDateTime(dt); +} + + +} // namespace TimeUtils +} // namespace Gwenview diff --git a/src/gvcore/timeutils.h b/src/gvcore/timeutils.h new file mode 100644 index 0000000..5815965 --- /dev/null +++ b/src/gvcore/timeutils.h @@ -0,0 +1,44 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2006 Aurélien Gâteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef TIMEUTILS_H +#define TIMEUTILS_H + +#include + +class KFileItem; +class QString; + +namespace Gwenview { +namespace TimeUtils { + +/** + * Returns the time of an item, using EXIF info if available + */ +time_t getTime(const KFileItem*); + +QString formatTime(time_t); + +} // namespace TimeUtils +} // namespace Gwenview + + + +#endif /* TIMEUTILS_H */ diff --git a/src/gvcore/xcursor.cpp b/src/gvcore/xcursor.cpp new file mode 100644 index 0000000..79df377 --- /dev/null +++ b/src/gvcore/xcursor.cpp @@ -0,0 +1,190 @@ +/* This file is part of the KDE libraries + Copyright (C) 2003 Fredrik Hglund + Copyright (C) 2005 Lubos Lunak + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include + +#include + +#include "xcursor.h" + +#include +#include +#include + +#ifdef GV_HAVE_XCURSOR +#include +#include +#include +#endif + +namespace Gwenview { + +#ifdef GV_HAVE_XCURSOR +class XCursorFormat : public QImageFormat { +public: + XCursorFormat(); + virtual int decode(QImage& img, QImageConsumer* consumer, + const uchar* buffer, int length); + QByteArray array; + int pos; + bool was_seek_error; +}; + +extern "C" +int xcursor_read( XcursorFile* file, unsigned char* buf, int len ) +{ + XCursorFormat* data = reinterpret_cast< XCursorFormat* >( file->closure ); + if( int( data->array.size()) - data->pos < len ) + { + data->was_seek_error = true; + len = data->array.size() - data->pos; + } + memcpy( buf, data->array.data() + data->pos, len ); + data->pos += len; + return len; +} + +extern "C" +int xcursor_write( XcursorFile*, unsigned char*, int ) +{ + assert( false ); // not write support + return 0; +} + +extern "C" +int xcursor_seek( XcursorFile* file, long offset, int whence ) +{ + XCursorFormat* data = reinterpret_cast< XCursorFormat* >( file->closure ); + if( whence == SEEK_CUR ) + offset += data->pos; + else if( whence == SEEK_END ) + offset = data->array.size() + offset; + if( offset < 0 || offset >= int( data->array.size())) + { + data->was_seek_error = true; + return -1; + } + data->pos = offset; + return 0; +} + +XCursorFormat::XCursorFormat() +{ +} + +int XCursorFormat::decode(QImage& img, QImageConsumer* cons, + const uchar* buffer, int length) +{ + if( length > 0 ) + { + int old_size = array.size(); + array.resize( old_size + length ); + memcpy( array.data() + old_size, buffer, length ); + } +// Qt's image async IO and Xcursor library have so nicely incompatible data reading :-/ +// Xcursor can read a file only as a whole. One can provide XcursorFile with functions +// for reading, writing and seeking. And seeking is the stupid part on Xcursor's side, +// as there's no way to suspend reading until more data is available. This means we +// basically have to read the whole file first. However, Qt's image async IO just keeps +// feeding data and when there's end of the data it just does nothing and doesn't tell +// the decoder. +// So the trick will be calling XcursorXcFileLoadImage() but whenever there will be +// a seeking/reading error, then the function will fail and we'll try again when there's +// more data. Also, reading everything first means we can't return without processing +// further data after reaching end of a frame in the input as decode() doc says, but oh well. + XcursorFile file; + file.closure = this; + file.read = xcursor_read; + file.write = xcursor_write; + file.seek = xcursor_seek; + pos = 0; + was_seek_error = false; + XcursorImages *cursors = XcursorXcFileLoadImages( &file, 1024 ); // largest possible cursor size + if ( cursors ) + { + for( int cur = 0; + cur < cursors->nimage; + ++cur ) + { + XcursorImage* cursor = cursors->images[ cur ]; + img = QImage( reinterpret_cast( cursor->pixels ), + cursor->width, cursor->height, 32, NULL, 0, QImage::BigEndian ); + img.setAlphaBuffer( true ); + // Convert the image to non-premultiplied alpha + Q_UINT32 *pixels = reinterpret_cast( img.bits() ); + for ( int i = 0; i < (img.width() * img.height()); i++ ) + { + float alpha = qAlpha( pixels[i] ) / 255.0; + if ( alpha > 0.0 && alpha < 1.0 ) + pixels[i] = qRgba( int( qRed(pixels[i]) / alpha ), + int( qGreen(pixels[i]) / alpha ), + int( qBlue(pixels[i]) / alpha ), + qAlpha(pixels[i]) ); + } + // Create a deep copy of the image so the image data is preserved + img = img.copy(); + if( cons ) + { + if( cur == 0 ) + { + cons->setSize( img.width(), img.height()); + if( cursors->nimage > 1 ) + cons->setLooping( 0 ); + } + cons->changed( QRect( QPoint( 0, 0 ), img.size())); + cons->frameDone(); + cons->setFramePeriod( cursor->delay ); + } + } + XcursorImagesDestroy( cursors ); + if( cons ) + cons->end(); + return length; + } + else if( was_seek_error ) // try again next time + return length; + return -1; // failure +} +#endif + +QImageFormat* XCursorFormatType::decoderFor( + const uchar* buffer, int length) +{ +#ifdef GV_HAVE_XCURSOR + if (length < 4) return 0; + if (buffer[0]=='X' + && buffer[1]=='c' + && buffer[2]=='u' + && buffer[3]=='r') + return new XCursorFormat; +#else + Q_UNUSED( buffer ); + Q_UNUSED( length ); +#endif + return 0; +} + +const char* XCursorFormatType::formatName() const +{ + return "XCursor"; +} + + +} // namespace diff --git a/src/gvcore/xcursor.h b/src/gvcore/xcursor.h new file mode 100644 index 0000000..27bec9a --- /dev/null +++ b/src/gvcore/xcursor.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE libraries + Copyright (C) 2003 Fredrik Hglund + Copyright (C) 2005 Lubos Lunak + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef gvxcursor_h +#define gvxcursor_h + +#include + +namespace Gwenview { + +class XCursorFormatType : public QImageFormatType { +public: + QImageFormat* decoderFor(const uchar* buffer, int length); + const char* formatName() const; +}; + +// ----------------------------------------------------------------------------- +} // namespace + +#endif // gvxcursor_h diff --git a/src/gvcore/xpm.cpp b/src/gvcore/xpm.cpp new file mode 100644 index 0000000..ce7656f --- /dev/null +++ b/src/gvcore/xpm.cpp @@ -0,0 +1,439 @@ +/* This file is based on qt-3.3.2/src/qimage.cpp , plus it includes + * a fix from qt-bugs@ issue #49934. Original copyright follows. + */ +/**************************************************************************** +** +** +** Implementation of QImage and QImageIO classes +** +** Created : 950207 +** +** Copyright (C) 1992-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. +** +**********************************************************************/ + +/* + + This code is xpm loader copied from qimage.cpp, with changes making it + possible to use this class from another thread. The problem is that + QColor::setNamedColor() isn't reentrant without thread-safe Xlib, + i.e. without XInitThreads() called. Current KDE applications + don't call XInitThreads(), and since it needs to be the very first + Xlib function called, and Gwenview is also a KPart, it's not possible + to rely on Xlib being thread-safe. + + Changes are marked using #ifdef GV_XPM_CHANGES. + +*/ + +#define GV_XPM_CHANGES + +#include "xpm.h" + +#include +#include +#include + +#include "threadgate.h" + +namespace Gwenview { + +// Qt code start --------------------------- +static QString fbname( const QString &fileName ) // get file basename (sort of) +{ + QString s = fileName; + if ( !s.isEmpty() ) { + int i; + if ( (i = s.findRev('/')) >= 0 ) + s = s.mid( i ); + if ( (i = s.findRev('\\')) >= 0 ) + s = s.mid( i ); + QRegExp r( QString::fromLatin1("[a-zA-Z][a-zA-Z0-9_]*") ); + int p = r.search( s ); + if ( p == -1 ) + s.truncate( 0 ); + else + s = s.mid( p, r.matchedLength() ); + } + if ( s.isEmpty() ) + s = QString::fromLatin1( "dummy" ); + return s; +} + +/***************************************************************************** + XPM image read/write functions + *****************************************************************************/ + + +// Skip until ", read until the next ", return the rest in *buf +// Returns FALSE on error, TRUE on success + +static bool read_xpm_string( QCString &buf, QIODevice *d, + const char * const *source, int &index ) +{ + if ( source ) { + buf = source[index++]; + return TRUE; + } + + if ( buf.size() < 69 ) //# just an approximation + buf.resize( 123 ); + + buf[0] = '\0'; + int c; + int i; + while ( (c=d->getch()) != EOF && c != '"' ) { } + if ( c == EOF ) { + return FALSE; + } + i = 0; + while ( (c=d->getch()) != EOF && c != '"' ) { + if ( i == (int)buf.size() ) + buf.resize( i*2+42 ); + buf[i++] = c; + } + if ( c == EOF ) { + return FALSE; + } + + if ( i == (int)buf.size() ) // always use a 0 terminator + buf.resize( i+1 ); + buf[i] = '\0'; + return TRUE; +} + + + +static int nextColorSpec(const QCString & buf) +{ + int i = buf.find(" c "); + if (i < 0) + i = buf.find(" g "); + if (i < 0) + i = buf.find(" g4 "); + if (i < 0) + i = buf.find(" m "); + if (i < 0) + i = buf.find(" s "); + return i; +} + +// +// INTERNAL +// +// Reads an .xpm from either the QImageIO or from the QString *. +// One of the two HAS to be 0, the other one is used. +// + +static void read_xpm_image_or_array( QImageIO * iio, const char * const * source, + QImage & image) +{ + QCString buf; + QIODevice *d = 0; + buf.resize( 200 ); + + int i, cpp, ncols, w, h, index = 0; + + if ( iio ) { + iio->setStatus( 1 ); + d = iio ? iio->ioDevice() : 0; + d->readLine( buf.data(), buf.size() ); // "/* XPM */" + QRegExp r( QString::fromLatin1("/\\*.XPM.\\*/") ); + if ( buf.find(r) == -1 ) + return; // bad magic + } else if ( !source ) { + return; + } + + if ( !read_xpm_string( buf, d, source, index ) ) + return; + + if ( sscanf( buf, "%d %d %d %d", &w, &h, &ncols, &cpp ) < 4 ) + return; // < 4 numbers parsed + + if ( cpp > 15 ) + return; + + if ( ncols > 256 ) { + image.create( w, h, 32 ); + } else { + image.create( w, h, 8, ncols ); + } + + if (image.isNull()) + return; + + QMap colorMap; + int currentColor; + + for( currentColor=0; currentColor < ncols; ++currentColor ) { + if ( !read_xpm_string( buf, d, source, index ) ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QImage: XPM color specification missing"); +#endif + return; + } + QString index; + index = buf.left( cpp ); + buf = buf.mid( cpp ).simplifyWhiteSpace().lower(); + buf.prepend( " " ); + i = nextColorSpec(buf); + if ( i < 0 ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QImage: XPM color specification is missing: %s", buf.data()); +#endif + return; // no c/g/g4/m/s specification at all + } + buf = buf.mid( i+3 ); + // Strip any other colorspec + int end = nextColorSpec(buf); + if (end != -1) + buf.truncate(end); + buf = buf.stripWhiteSpace(); + if ( buf == "none" ) { + image.setAlphaBuffer( TRUE ); + int transparentColor = currentColor; + if ( image.depth() == 8 ) { + image.setColor( transparentColor, + RGB_MASK & qRgb(198,198,198) ); + colorMap.insert( index, transparentColor ); + } else { + QRgb rgb = RGB_MASK & qRgb(198,198,198); + colorMap.insert( index, rgb ); + } + } else { + if ( ((buf.length()-1) % 3) && (buf[0] == '#') ) { + buf.truncate (((buf.length()-1) / 4 * 3) + 1); // remove alpha channel left by imagemagick + } +#ifdef GV_XPM_CHANGES + QColor c = ThreadGate::instance()->color( buf.data()); +#else + QColor c( buf.data() ); +#endif + if ( image.depth() == 8 ) { + image.setColor( currentColor, 0xff000000 | c.rgb() ); + colorMap.insert( index, currentColor ); + } else { + QRgb rgb = 0xff000000 | c.rgb(); + colorMap.insert( index, rgb ); + } + } + } + + // Read pixels + for( int y=0; ysetImage( image ); + iio->setStatus( 0 ); // image ok + } +} + + +static void read_xpm_image( QImageIO * iio ) +{ + QImage i; + (void)read_xpm_image_or_array( iio, 0, i ); + return; +} + + +static const char* xpm_color_name( int cpp, int index ) +{ + static char returnable[5]; + static const char code[] = ".#abcdefghijklmnopqrstuvwxyzABCD" + "EFGHIJKLMNOPQRSTUVWXYZ0123456789"; + // cpp is limited to 4 and index is limited to 64^cpp + if ( cpp > 1 ) { + if ( cpp > 2 ) { + if ( cpp > 3 ) { + returnable[3] = code[index % 64]; + index /= 64; + } else + returnable[3] = '\0'; + returnable[2] = code[index % 64]; + index /= 64; + } else + returnable[2] = '\0'; + // the following 4 lines are a joke! + if ( index == 0 ) + index = 64*44+21; + else if ( index == 64*44+21 ) + index = 0; + returnable[1] = code[index % 64]; + index /= 64; + } else + returnable[1] = '\0'; + returnable[0] = code[index]; + + return returnable; +} + + +// write XPM image data +static void write_xpm_image( QImageIO * iio ) +{ + if ( iio ) + iio->setStatus( 1 ); + else + return; + + // ### 8-bit case could be made faster + QImage image; + if ( iio->image().depth() != 32 ) + image = iio->image().convertDepth( 32 ); + else + image = iio->image(); + + QMap colorMap; + + int w = image.width(), h = image.height(), ncolors = 0; + int x, y; + + // build color table + for( y=0; y k; k *= 64 ) { + ++cpp; + // limit to 4 characters per pixel + // 64^4 colors is enough for a 4096x4096 image + if ( cpp > 4) + break; + } + + QString line; + + // write header + QTextStream s( iio->ioDevice() ); + s << "/* XPM */" << endl + << "static char *" << fbname(iio->fileName()) << "[]={" << endl + << "\"" << w << " " << h << " " << ncolors << " " << cpp << "\""; + + // write palette + QMap::Iterator c = colorMap.begin(); + while ( c != colorMap.end() ) { + QRgb color = c.key(); + if ( image.hasAlphaBuffer() && color == (color & RGB_MASK) ) + line.sprintf( "\"%s c None\"", + xpm_color_name(cpp, *c) ); + else + line.sprintf( "\"%s c #%02x%02x%02x\"", + xpm_color_name(cpp, *c), + qRed(color), + qGreen(color), + qBlue(color) ); + ++c; + s << "," << endl << line; + } + + // write pixels, limit to 4 characters per pixel + line.truncate( cpp*w ); + for( y=0; y 1 ) { + line[cc++] = chars[1]; + if ( cpp > 2 ) { + line[cc++] = chars[2]; + if ( cpp > 3 ) { + line[cc++] = chars[3]; + } + } + } + } + s << "," << endl << "\"" << line << "\""; + } + s << "};" << endl; + + iio->setStatus( 0 ); +} + +// Qt code end --------------------------- + +XPM::XPM() +{ + QImageIO::inputFormats(); // trigger registration of Qt's handlers + QImageIO::defineIOHandler( "XPM", "/\\*.XPM.\\*/", "T", + read_xpm_image, write_xpm_image ); +} + +} // namespace diff --git a/src/gvcore/xpm.h b/src/gvcore/xpm.h new file mode 100644 index 0000000..f506ea6 --- /dev/null +++ b/src/gvcore/xpm.h @@ -0,0 +1,54 @@ +/* This file is based on qt-3.3.2/src/qimage.cpp . Original + * copyright follows. + */ +/**************************************************************************** +** +** +** Implementation of QImage and QImageIO classes +** +** Created : 950207 +** +** Copyright (C) 1992-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. +** +**********************************************************************/ + +#ifndef gvxpm_h +#define gvxpm_h + +namespace Gwenview { + +class XPM { +public: + XPM(); +}; + +// ----------------------------------------------------------------------------- +} // namespace + +#endif // gvxpm_h diff --git a/src/gvdirpart/Makefile.am b/src/gvdirpart/Makefile.am new file mode 100644 index 0000000..039267d --- /dev/null +++ b/src/gvdirpart/Makefile.am @@ -0,0 +1,23 @@ +INCLUDES = -I$(srcdir)/.. $(all_includes) + +# These are not really libraries, but modules dynamically opened. +# So they should be installed in kde_module_dir, which is usually $kde_prefix/lib/kde3 +kde_module_LTLIBRARIES = libgvdirpart.la + +libgvdirpart_la_SOURCES = gvdirpart.cpp gvdirpartconfig.kcfgc +libgvdirpart_la_LIBADD = $(LIB_KPARTS) ../gvcore/libgwenviewcore.la +libgvdirpart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) + +# Automatically generate moc files +METASOURCES = AUTO + +# Install the XML-GUI file to its correct location +gvdir = $(kde_datadir)/gvdirpart +gv_DATA = gvdirpart.rc + +# Install the .desktop file into the kde_services directory +kde_services_DATA = gvdirpart.desktop + +KDE_ICON = AUTO + +kde_kcfg_DATA = gvdirpartconfig.kcfg diff --git a/src/gvdirpart/cr16-app-gvdirpart.png b/src/gvdirpart/cr16-app-gvdirpart.png new file mode 100644 index 0000000..d49bc5b Binary files /dev/null and b/src/gvdirpart/cr16-app-gvdirpart.png differ diff --git a/src/gvdirpart/cr22-app-gvdirpart.png b/src/gvdirpart/cr22-app-gvdirpart.png new file mode 100644 index 0000000..00eaab2 Binary files /dev/null and b/src/gvdirpart/cr22-app-gvdirpart.png differ diff --git a/src/gvdirpart/cr32-app-gvdirpart.png b/src/gvdirpart/cr32-app-gvdirpart.png new file mode 100644 index 0000000..1a68bf4 Binary files /dev/null and b/src/gvdirpart/cr32-app-gvdirpart.png differ diff --git a/src/gvdirpart/crsc-app-gvdirpart.svg b/src/gvdirpart/crsc-app-gvdirpart.svg new file mode 100644 index 0000000..c470051 --- /dev/null +++ b/src/gvdirpart/crsc-app-gvdirpart.svg @@ -0,0 +1,587 @@ + + + + diff --git a/src/gvdirpart/gvdirpart.cpp b/src/gvdirpart/gvdirpart.cpp new file mode 100644 index 0000000..f85f06d --- /dev/null +++ b/src/gvdirpart/gvdirpart.cpp @@ -0,0 +1,288 @@ +/* +Copyright 2004 Jonathan Riddell + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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 Steet, Fifth Floor, Boston, MA 02111-1307, USA. + +*/ +#include "gvdirpart.moc" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "gvdirpartconfig.h" + +namespace Gwenview { + +// For now let's duplicate +const char CONFIG_CACHE_GROUP[]="cache"; + + +//Factory Code +typedef KParts::GenericFactory GVDirFactory; +K_EXPORT_COMPONENT_FACTORY( libgvdirpart /*library name*/, GVDirFactory ) + +GVDirPart::GVDirPart(QWidget* parentWidget, const char* /*widgetName*/, QObject* parent, const char* name, + const QStringList &) : KParts::ReadOnlyPart( parent, name ) { + GVDirFactory::instance()->iconLoader()->addAppDir( "gwenview"); + setInstance( GVDirFactory::instance() ); + KGlobal::locale()->insertCatalogue("gwenview"); + KGlobal::locale()->setActiveCatalogue("gwenview"); + + mBrowserExtension = new GVDirPartBrowserExtension(this); + + mSplitter = new QSplitter(Qt::Horizontal, parentWidget, "gwenview-kpart-splitter"); + mSplitter->setFocusPolicy(QWidget::ClickFocus); + mSplitter->setOpaqueResize(true); + + // Create the widgets + mDocument = new Document(this); + mFileViewController = new FileViewController(mSplitter, actionCollection()); + int width=GVDirPartConfig::fileViewWidth(); + if (width!=-1) { + mFileViewController->resize(width, 10); + } + mImageView = new ImageView(mSplitter, mDocument, actionCollection()); + mSplitter->setResizeMode(mFileViewController, QSplitter::KeepSize); + + mSlideShow = new SlideShow(mDocument); + + setWidget(mSplitter); + + KStdAction::saveAs( mDocument, SLOT(saveAs()), actionCollection(), "saveAs" ); + new KAction(i18n("Rotate &Left"), "rotate_ccw", CTRL + Key_L, this, SLOT(rotateLeft()), actionCollection(), "rotate_left"); + new KAction(i18n("Rotate &Right"), "rotate_cw", CTRL + Key_R, this, SLOT(rotateRight()), actionCollection(), "rotate_right"); + + connect(mFileViewController, SIGNAL(requestContextMenu(const QPoint&, bool)), + mBrowserExtension, SLOT(openFileViewContextMenu(const QPoint&, bool)) ); + + connect(mFileViewController, SIGNAL(urlChanged(const KURL&)), + mDocument, SLOT(setURL(const KURL&)) ); + + connect(mFileViewController, SIGNAL(directoryChanged(const KURL&)), + this, SLOT(directoryChanged(const KURL&)) ); + + connect(mFileViewController, SIGNAL(selectionChanged()), + mBrowserExtension, SLOT(updateActions()) ); + + connect(mImageView, SIGNAL(requestContextMenu(const QPoint&)), + mBrowserExtension, SLOT(openImageViewContextMenu(const QPoint&)) ); + + connect(mSlideShow, SIGNAL(nextURL(const KURL&)), + this, SLOT(slotSlideShowChanged(const KURL&)) ); + + connect(mDocument, SIGNAL(loaded(const KURL&)), + this, SLOT(loaded(const KURL&)) ); + + // For wheel browsing + connect(mImageView, SIGNAL(selectPrevious()), + mFileViewController, SLOT(slotSelectPrevious()) ); + connect(mImageView, SIGNAL(selectNext()), + mFileViewController, SLOT(slotSelectNext()) ); + + mToggleSlideShow = new KToggleAction(i18n("Slide Show..."), "slideshow", 0, this, SLOT(toggleSlideShow()), actionCollection(), "slideshow"); + mToggleSlideShow->setCheckedState( i18n("Stop Slide Show" )); + + setXMLFile( "gvdirpart/gvdirpart.rc" ); + mBrowserExtension->updateActions(); +} + +GVDirPart::~GVDirPart() { + GVDirPartConfig::setFileViewWidth(mFileViewController->width()); + GVDirPartConfig::writeConfig(); + delete mSlideShow; +} + + +void GVDirPart::partActivateEvent(KParts::PartActivateEvent* event) { + if (event->activated()) { + KConfig* config=new KConfig("gwenviewrc"); + Cache::instance()->readConfig(config,CONFIG_CACHE_GROUP); + delete config; + } +} + + +KAboutData* GVDirPart::createAboutData() { + KAboutData* aboutData = new KAboutData( "gvdirpart", I18N_NOOP("GVDirPart"), + "0.1", I18N_NOOP("Image Browser"), + KAboutData::License_GPL, + "(c) 2004, Jonathan Riddell "); + return aboutData; +} + +bool GVDirPart::openFile() { + //unused because openURL implemented + + //mDocument->setFilename(mFile); + return true; +} + +bool GVDirPart::openURL(const KURL& url) { + if (!url.isValid()) { + return false; + } + + emit started( 0 ); + m_url = url; + m_url.adjustPath(1); + + emit setWindowCaption( m_url.prettyURL() ); + mFileViewController->setDirURL(m_url); + + return true; +} + +void GVDirPart::loaded(const KURL& url) { + QString caption = url.filename(); + if( !mDocument->image().isNull()) + caption += QString(" %1 x %2").arg(mDocument->width()).arg(mDocument->height()); + emit setWindowCaption(caption); + emit completed(); +} + +KURL GVDirPart::pixmapURL() { + return mDocument->url(); +} + +void GVDirPart::toggleSlideShow() { + if (mToggleSlideShow->isChecked()) { + KURL::List list; + KFileItemListIterator it( *mFileViewController->currentFileView()->items() ); + for ( ; it.current(); ++it ) { + KFileItem* item=it.current(); + if (!item->isDir() && !Archive::fileItemIsArchive(item)) { + list.append(item->url()); + } + } + if (list.count()==0) { + mToggleSlideShow->setChecked(false); + return; + } + //FIXME turn on full screen here (anyone know how?) + mSlideShow->start(list); + } else { + //FIXME turn off full screen here + mSlideShow->stop(); + } +} + +void GVDirPart::print() { + KPrinter printer; + if ( !mDocument->filename().isEmpty() ) { + printer.setDocName( m_url.filename() ); + KPrinter::addDialogPage( new PrintDialogPage( mDocument, mImageView, "GV page")); + + if (printer.setup(mImageView, QString::null, true)) { + mDocument->print(&printer); + } + } +} + +void GVDirPart::rotateLeft() { + mDocument->transform(ImageUtils::ROT_270); +} + +void GVDirPart::rotateRight() { + mDocument->transform(ImageUtils::ROT_90); +} + +void GVDirPart::directoryChanged(const KURL& dirURL) { + if( dirURL == m_url ) return; + emit mBrowserExtension->openURLRequest(dirURL); +} + +void GVDirPart::slotSlideShowChanged(const KURL& url) { + mDocument->setURL( url ); + mFileViewController->setFileNameToSelect( url.filename()); +} + + +/***** GVDirPartBrowserExtension *****/ + +GVDirPartBrowserExtension::GVDirPartBrowserExtension(GVDirPart* viewPart, const char* name) + :KParts::BrowserExtension(viewPart, name) { + mGVDirPart = viewPart; + emit enableAction("print", true ); +} + +GVDirPartBrowserExtension::~GVDirPartBrowserExtension() { +} + +void GVDirPartBrowserExtension::updateActions() { + bool somethingSelected = mGVDirPart->fileViewController()->selectionSize() != 0; + emit enableAction("trash", somethingSelected); + emit enableAction("del", somethingSelected); +} + +void GVDirPartBrowserExtension::del() { + FileViewController* fv = mGVDirPart->fileViewController(); + FileOperation::realDelete(fv->selectedURLs(), fv); + +} + +void GVDirPartBrowserExtension::trash() { + FileViewController* fv = mGVDirPart->fileViewController(); + FileOperation::trash(fv->selectedURLs(), fv); +} + + +void GVDirPartBrowserExtension::openFileViewContextMenu(const QPoint& pos, bool onItem) { + if (onItem) { + const KFileItemList* items = mGVDirPart->fileViewController()->currentFileView()->selectedItems(); + emit popupMenu(pos, *items); + } else { + emit popupMenu(pos, mGVDirPart->fileViewController()->dirURL(), 0); + } +} + + +void GVDirPartBrowserExtension::openImageViewContextMenu(const QPoint& pos) { + KURL url=mGVDirPart->url(); + QString mimeType=KMimeType::findByURL(url)->name(); + emit popupMenu(pos, url, mimeType); +} + + +void GVDirPartBrowserExtension::print() { + mGVDirPart->print(); +} + +} // namespace diff --git a/src/gvdirpart/gvdirpart.desktop b/src/gvdirpart/gvdirpart.desktop new file mode 100644 index 0000000..f2632c6 --- /dev/null +++ b/src/gvdirpart/gvdirpart.desktop @@ -0,0 +1,44 @@ +[Desktop Entry] +Type=Service +Name=Image View +Name[bg]=Преглед на изображения +Name[br]=Gwell ar skeudennoù +Name[ca]=Vista d'imatge +Name[cs]=Prohlížeč obrázků +Name[da]=Billedvisning +Name[de]=Bildbetrachter +Name[el]=Προβολή εικόνων +Name[es]=Visor de imágenes +Name[et]=Pildinäitaja +Name[fa]=نمای تصویر +Name[fr]=Aperçu d'images +Name[gl]=Visor de Imaxes +Name[hr]=Pregled slike +Name[hu]=Képnézegető +Name[is]=Myndskoðun +Name[it]=Vista immagini +Name[ja]=画像表示 +Name[ka]=სურათების ნახვა +Name[ms]=Lihat Imej +Name[nds]=Bildansicht +Name[nl]=Afbeeldingweergave +Name[pa]=ਚਿੱਤਰ ਝਲਕ +Name[pt]=Visualizador de Imagens +Name[pt_BR]=Visualizador de Imagens +Name[ru]=Просмотр изображений +Name[sk]=Zobrazenie obrázku +Name[sr]=Приказ слика +Name[sr@Latn]=Prikaz slika +Name[sv]=Bildvisare +Name[ta]=பிம்பக் காட்சி +Name[tg]=Намоишгари тасвир +Name[tr]=Resim Görünümü +Name[uk]=Перегляд зображень +Name[vi]=Xem ảnh +Name[xx]=xxImage Viewxx +Name[zh_CN]=图像查看 +MimeType=inode/directory +ServiceTypes=KParts/ReadOnlyPart +X-KDE-Library=libgvdirpart +InitialPreference=5 +Icon=gvdirpart diff --git a/src/gvdirpart/gvdirpart.h b/src/gvdirpart/gvdirpart.h new file mode 100644 index 0000000..08b5626 --- /dev/null +++ b/src/gvdirpart/gvdirpart.h @@ -0,0 +1,174 @@ +/* +Copyright 2004 Jonathan Riddell + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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 Steet, Fifth Floor, Boston, MA 02111-1307, USA. + +*/ +#ifndef __gvdirpart_h__ +#define __gvdirpart_h__ + +#include +#include + +// Forward declarations +class QPoint; +class QSplitter; +class KAboutData; +class KAction; +class KToggleAction; + +namespace Gwenview { + +class ImageView; +class FileViewController; +class Document; +class SlideShow; + +class GVDirPart; + +/** + * The browser extension is an attribute of GVImagePart and provides + * some services to Konqueror. All Konqueror KParts have one. + */ +class GVDirPartBrowserExtension: public KParts::BrowserExtension { + Q_OBJECT + +public: + GVDirPartBrowserExtension(GVDirPart* viewPart, const char* name=0L); + ~GVDirPartBrowserExtension(); + +public slots: + void updateActions(); + + void trash(); + void del(); + + void print(); + +private slots: + void openFileViewContextMenu(const QPoint&, bool onItem); + void openImageViewContextMenu(const QPoint&); + +private: + GVDirPart* mGVDirPart; +}; + +/** + * A Read Only KPart to browse directories and their images using Gwenview + */ +class GVDirPart : public KParts::ReadOnlyPart { + Q_OBJECT +public: + GVDirPart(QWidget*, const char*, QObject*, const char*, const QStringList &); + virtual ~GVDirPart(); + + /** + * Return information about the part + */ + static KAboutData* createAboutData(); + + /** + * Returns the name of the current file in the pixmap + */ + KURL pixmapURL(); + + /** + * Print the image being viewed if there is one + */ + void print(); + + FileViewController* fileViewController() const { return mFileViewController; } + + +protected: + void partActivateEvent(KParts::PartActivateEvent* event); + + /** + * Unused because openURL() is implemented but required to be + * implemented. + */ + virtual bool openFile(); + + /** + * Tell the widgets the URL to browse. Sets the window + * caption and saves URL to m_url (important for history and + * others). + */ + virtual bool openURL(const KURL& url); + +protected slots: + /** + * Turns the slide show on or off + */ + void toggleSlideShow(); + + /** + * Sets Konqueror's caption, statusbar and emits completed(). + * Called by loaded() signal in GVDocument + */ + void loaded(const KURL& url); + + /** + * Rotates the current image 90 degrees counter clockwise + */ + void rotateLeft(); + + /** + * Rotates the current image 90 degrees clockwise + */ + void rotateRight(); + + void directoryChanged(const KURL& dirURL); + + void slotSlideShowChanged( const KURL& ); + +protected: + /** + * The component's widget, contains the files view on the left + * and scroll view on the right. + */ + QSplitter* mSplitter; + + /** + * Scroll widget + */ + ImageView* mImageView; + + /** + * Holds the image + */ + Document* mDocument; + + /** + * Shows the directory's files and folders + */ + + FileViewController* mFileViewController; + + /** + * This inherits from KParts::BrowserExtention and supplies + * some extra functionality to Konqueror. + */ + GVDirPartBrowserExtension* mBrowserExtension; + + /** + * Action turns on slide show + */ + KToggleAction* mToggleSlideShow; + SlideShow* mSlideShow; +}; + +} // namespace +#endif diff --git a/src/gvdirpart/gvdirpart.rc b/src/gvdirpart/gvdirpart.rc new file mode 100644 index 0000000..61717b9 --- /dev/null +++ b/src/gvdirpart/gvdirpart.rc @@ -0,0 +1,46 @@ + + + + &File + + + + + + + &View + + + + + &Colors + + + + + + + + + + + + + + + + + + +Main Toolbar + + + + + + + + + + + diff --git a/src/gvdirpart/gvdirpartconfig.kcfg b/src/gvdirpart/gvdirpartconfig.kcfg new file mode 100644 index 0000000..5296e51 --- /dev/null +++ b/src/gvdirpart/gvdirpartconfig.kcfg @@ -0,0 +1,10 @@ + + + + + + + -1 + + + diff --git a/src/gvdirpart/gvdirpartconfig.kcfgc b/src/gvdirpart/gvdirpartconfig.kcfgc new file mode 100644 index 0000000..e89b1be --- /dev/null +++ b/src/gvdirpart/gvdirpartconfig.kcfgc @@ -0,0 +1,4 @@ +File=gvdirpartconfig.kcfg +ClassName=GVDirPartConfig +Singleton=true +Mutators=true diff --git a/src/gvdirpart/hi16-app-gvdirpart.png b/src/gvdirpart/hi16-app-gvdirpart.png new file mode 100644 index 0000000..175c0df Binary files /dev/null and b/src/gvdirpart/hi16-app-gvdirpart.png differ diff --git a/src/gvdirpart/hi22-app-gvdirpart.png b/src/gvdirpart/hi22-app-gvdirpart.png new file mode 100644 index 0000000..d590c70 Binary files /dev/null and b/src/gvdirpart/hi22-app-gvdirpart.png differ diff --git a/src/gvdirpart/hi32-app-gvdirpart.png b/src/gvdirpart/hi32-app-gvdirpart.png new file mode 100644 index 0000000..9f3b269 Binary files /dev/null and b/src/gvdirpart/hi32-app-gvdirpart.png differ diff --git a/src/gvdirpart/hisc-app-gvdirpart.svg b/src/gvdirpart/hisc-app-gvdirpart.svg new file mode 100644 index 0000000..8846fb5 --- /dev/null +++ b/src/gvdirpart/hisc-app-gvdirpart.svg @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/src/gvimagepart/Makefile.am b/src/gvimagepart/Makefile.am new file mode 100644 index 0000000..6ed0ff3 --- /dev/null +++ b/src/gvimagepart/Makefile.am @@ -0,0 +1,20 @@ +INCLUDES = -I$(srcdir)/.. $(all_includes) + +# These are not really libraries, but modules dynamically opened. +# So they should be installed in kde_module_dir, which is usually $kde_prefix/lib/kde3 +kde_module_LTLIBRARIES = libgvimagepart.la + +libgvimagepart_la_SOURCES = gvimagepart.cpp +libgvimagepart_la_LIBADD = $(LIB_KPARTS) ../gvcore/libgwenviewcore.la +libgvimagepart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) + +# Automatically generate moc files +METASOURCES = AUTO + +# Install the XML-UI file to its correct location +gvdir = $(kde_datadir)/gvimagepart +gv_DATA = gvimagepart.rc gvimagepartpopup.rc + +# Install the .desktop file into the kde_services directory +kde_services_DATA = gvimagepart.desktop + diff --git a/src/gvimagepart/gvimagepart.cpp b/src/gvimagepart/gvimagepart.cpp new file mode 100644 index 0000000..5750445 --- /dev/null +++ b/src/gvimagepart/gvimagepart.cpp @@ -0,0 +1,450 @@ +/* +Copyright 2004 Jonathan Riddell + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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 Steet, Fifth Floor, Boston, MA 02111-1307, USA. + +*/ +#include "gvimagepart.moc" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +namespace Gwenview { +// For now let's duplicate +const char CONFIG_CACHE_GROUP[]="cache"; + +#undef ENABLE_LOG +#undef LOG +#define ENABLE_LOG +#ifdef ENABLE_LOG +#define LOG(x) kdDebug() << k_funcinfo << x << endl +#else +#define LOG(x) ; +#endif + + +static bool storeData(QWidget* parent, QFile* file, const QByteArray& data) { + uint sizeWritten = file->writeBlock(data); + if (sizeWritten != data.size()) { + KMessageBox::error( + parent, + i18n("Could not save image to a temporary file")); + return false; + } + return true; +} + + +//Factory Code +typedef KParts::GenericFactory GVImageFactory; +K_EXPORT_COMPONENT_FACTORY( libgvimagepart /*library name*/, GVImageFactory ) + +GVImagePart::GVImagePart(QWidget* parentWidget, const char* /*widgetName*/, QObject* parent, + const char* name, const QStringList &) + : KParts::ReadOnlyPart( parent, name ) + , mPrefetch( NULL ) + , mLastDirection( DirectionUnknown ) { + GVImageFactory::instance()->iconLoader()->addAppDir( "gwenview"); + setInstance( GVImageFactory::instance() ); + KGlobal::locale()->insertCatalogue("gwenview"); + KGlobal::locale()->setActiveCatalogue("gwenview"); + + mBrowserExtension = new GVImagePartBrowserExtension(this); + + // Create the widgets + mDocument = new Document(this); + connect( mDocument, SIGNAL( loading()), SLOT( slotLoading())); + connect( mDocument, SIGNAL( loaded(const KURL&)), SLOT( slotLoaded(const KURL&))); + mImageView = new ImageView(parentWidget, mDocument, actionCollection()); + connect( mImageView, SIGNAL(requestContextMenu(const QPoint&)), + this, SLOT(openContextMenu(const QPoint&)) ); + setWidget(mImageView); + + mDirLister = new KDirLister; + mDirLister->setAutoErrorHandlingEnabled( false, 0 ); + mDirLister->setMainWindow(KApplication::kApplication()->mainWidget()); + connect( mDirLister, SIGNAL( clear()), SLOT( dirListerClear())); + connect( mDirLister, SIGNAL( newItems( const KFileItemList& )), + SLOT( dirListerNewItems( const KFileItemList& ))); + connect(mDirLister,SIGNAL(deleteItem(KFileItem*)), + SLOT(dirListerDeleteItem(KFileItem*)) ); + + QStringList mimeTypes=MimeTypeUtils::rasterImageMimeTypes(); + mDirLister->setMimeFilter(mimeTypes); + mPreviousImage=new KAction(i18n("&Previous Image"), + QApplication::reverseLayout() ? "1rightarrow":"1leftarrow", Key_BackSpace, + this,SLOT(slotSelectPrevious()), actionCollection(), "previous"); + mNextImage=new KAction(i18n("&Next Image"), + QApplication::reverseLayout() ? "1leftarrow":"1rightarrow", Key_Space, + this,SLOT(slotSelectNext()), actionCollection(), "next"); + updateNextPrevious(); + + KStdAction::saveAs( this, SLOT(saveAs()), actionCollection(), "saveAs" ); + new KAction(i18n("Rotate &Left"), "rotate_ccw", CTRL + Key_L, this, SLOT(rotateLeft()), actionCollection(), "rotate_left"); + new KAction(i18n("Rotate &Right"), "rotate_cw", CTRL + Key_R, this, SLOT(rotateRight()), actionCollection(), "rotate_right"); + + setXMLFile( "gvimagepart/gvimagepart.rc" ); +} + +GVImagePart::~GVImagePart() { + delete mDirLister; +} + + +void GVImagePart::partActivateEvent(KParts::PartActivateEvent* event) { + if (event->activated()) { + KConfig* config=new KConfig("gwenviewrc"); + Cache::instance()->readConfig(config,CONFIG_CACHE_GROUP); + delete config; + } + KParts::ReadOnlyPart::partActivateEvent( event ); +} + + +void GVImagePart::guiActivateEvent( KParts::GUIActivateEvent* event) { + // Stolen from KHTMLImage + // + // prevent the base implementation from emitting setWindowCaption with + // our url. It destroys our pretty, previously caption. Konq saves/restores + // the caption for us anyway. + if (event->activated()) { + return; + } + KParts::ReadOnlyPart::guiActivateEvent(event); +} + + +KAboutData* GVImagePart::createAboutData() { + KAboutData* aboutData = new KAboutData( "gvimagepart", I18N_NOOP("GVImagePart"), + "0.1", I18N_NOOP("Image Viewer"), + KAboutData::License_GPL, + "(c) 2004, Jonathan Riddell "); + return aboutData; +} + +bool GVImagePart::openURL(const KURL& url) { + if (!url.isValid()) { + return false; + } + KURL oldURLDir = m_url; + oldURLDir.setFileName( QString::null ); + KURL newURLDir = url; + newURLDir.setFileName( QString::null ); + bool sameDir = oldURLDir == newURLDir; + m_url = url; + emit started( 0 ); + if( mDocument->url() == url ) { // reload button in Konqy - setURL would return immediately + mDocument->reload(); + } else { + mDocument->setURL(url); + } + if( !sameDir ) { + mDirLister->openURL(mDocument->dirURL()); + mLastDirection = DirectionUnknown; + } + return true; +} + +QString GVImagePart::filePath() { + return m_file; +} + +void GVImagePart::slotLoading() { + emit setWindowCaption(mDocument->url().filename() + " - " + i18n("Loading...")); + // Set the location bar URL because we can arrive here if the user click on + // previous/next, which do not use openURLRequest + emit mBrowserExtension->setLocationBarURL(mDocument->url().pathOrURL()); + updateNextPrevious(); +} + +void GVImagePart::slotLoaded(const KURL& url) { + QString caption = url.filename() + QString(" - %1x%2").arg(mDocument->width()).arg(mDocument->height()); + emit setWindowCaption(caption); + emit completed(); + emit setStatusBarText(i18n("Done.")); + prefetchDone(); + mPrefetch = ImageLoader::loader( mLastDirection == DirectionPrevious ? previousURL() : nextURL(), + this, BUSY_PRELOADING ); + connect( mPrefetch, SIGNAL( imageLoaded( bool )), SLOT( prefetchDone())); +} + +void GVImagePart::prefetchDone() { + if( mPrefetch != NULL ) { + mPrefetch->release( this ); + } + mPrefetch = NULL; +} + +void GVImagePart::print() { + KPrinter printer; + + printer.setDocName( m_url.filename() ); + KPrinter::addDialogPage( new PrintDialogPage( mDocument, mImageView, "GV page")); + + if (printer.setup(mImageView, QString::null, true)) { + mDocument->print(&printer); + } +} + +void GVImagePart::rotateLeft() { + mDocument->transform(ImageUtils::ROT_270); +} + +void GVImagePart::rotateRight() { + mDocument->transform(ImageUtils::ROT_90); +} + +void GVImagePart::dirListerClear() { + mImagesInDirectory.clear(); + updateNextPrevious(); +} + +void GVImagePart::dirListerNewItems( const KFileItemList& list ) { + QPtrListIterator it(list); + for( ; it.current(); ++it ) { + mImagesInDirectory.append( (*it)->name()); + } + qHeapSort( mImagesInDirectory ); + updateNextPrevious(); +} + +void GVImagePart::dirListerDeleteItem( KFileItem* item ) { + mImagesInDirectory.remove( item->name()); + updateNextPrevious(); +} + +void GVImagePart::updateNextPrevious() { + QStringList::ConstIterator current = mImagesInDirectory.find( mDocument->filename()); + if( current == mImagesInDirectory.end()) { + mNextImage->setEnabled( false ); + mPreviousImage->setEnabled( false ); + return; + } + mPreviousImage->setEnabled( current != mImagesInDirectory.begin()); + ++current; + mNextImage->setEnabled( current != mImagesInDirectory.end()); +} + +KURL GVImagePart::nextURL() const { + QStringList::ConstIterator current = mImagesInDirectory.find( mDocument->filename()); + if( current == mImagesInDirectory.end()) { + return KURL(); + } + ++current; + if( current == mImagesInDirectory.end()) { + return KURL(); + } + KURL newURL = mDocument->dirURL(); + newURL.setFileName( *current ); + return newURL; +} + +void GVImagePart::slotSelectNext() { + KURL newURL = nextURL(); + if( newURL.isEmpty()) return; + mLastDirection = DirectionNext; + // Do not use mBrowserExtension->openURLRequest to avoid switching to + // another KPart + openURL(newURL); + emit mBrowserExtension->openURLNotify(); +} + +KURL GVImagePart::previousURL() const { + QStringList::ConstIterator current = mImagesInDirectory.find( mDocument->filename()); + if( current == mImagesInDirectory.end() || current == mImagesInDirectory.begin()) { + return KURL(); + } + --current; + KURL newURL = mDocument->dirURL(); + newURL.setFileName( *current ); + return newURL; +} + +void GVImagePart::slotSelectPrevious() { + KURL newURL = previousURL(); + if( newURL.isEmpty()) return; + mLastDirection = DirectionPrevious; + openURL(newURL); + emit mBrowserExtension->openURLNotify(); +} + + +void GVImagePart::saveAs() { + if (!mDocument->isModified()) { + saveOriginalAs(); + return; + } + + if (mDocument->canBeSaved()) { + mDocument->saveAs(); + return; + } + + KGuiItem saveItem(i18n("&Save Original"), "filesaveas"); + int result = KMessageBox::warningContinueCancel( + widget(), + i18n("Gwenview KPart can't save the modifications you made. Do you want to save the original image?"), + i18n("Warning"), + saveItem); + + if (result == KMessageBox::Cancel) return; + + saveOriginalAs(); +} + + +void GVImagePart::showJobError(KIO::Job* job) { + if (job->error() != 0) { + job->showErrorDialog(widget()); + } +} + + +void GVImagePart::saveOriginalAs() { + KURL srcURL = mDocument->url(); + KURL dstURL = KFileDialog::getSaveURL( + srcURL.fileName(), + QString::null, + widget()); + if (!dstURL.isValid()) return; + + // Try to get data from the cache to avoid downloading the image again. + QByteArray data = Cache::instance()->file(srcURL); + + if (data.size() == 0) { + // We need to read the image again. Let KIO::copy do the work. + KIO::Job* job = KIO::copy(srcURL, dstURL); + job->setWindow(widget()); + connect(job, SIGNAL(result(KIO::Job*)), + this, SLOT(showJobError(KIO::Job*)) ); + return; + } + + if (dstURL.isLocalFile()) { + // Destination is a local file, store it ourself + QString path = dstURL.path(); + QFile file(path); + if (!file.open(IO_WriteOnly)) { + KMessageBox::error( + widget(), + i18n("Could not open '%1' for writing.").arg(path)); + return; + } + storeData(widget(), &file, data); + return; + } + + // We need to send the data to a remote location + new DataUploader(widget(), data, dstURL); +} + + +DataUploader::DataUploader(QWidget* dialogParent, const QByteArray& data, const KURL& dstURL) +: mDialogParent(dialogParent) +{ + mTempFile.setAutoDelete(true); + + // Store it in a temp file + if (! storeData(dialogParent, mTempFile.file(), data) ) return; + + // Now upload it + KURL tmpURL; + tmpURL.setPath(mTempFile.name()); + KIO::Job* job = KIO::copy(tmpURL, dstURL); + job->setWindow(dialogParent); + connect(job, SIGNAL(result(KIO::Job*)), + this, SLOT(slotJobFinished(KIO::Job*)) ); +} + + +void DataUploader::slotJobFinished(KIO::Job* job) { + if (job->error() != 0) { + job->showErrorDialog(mDialogParent); + } + + delete this; +} + + +/** + * Overload KXMLGUIClient so that we can call setXML + */ +class PopupGUIClient : public KXMLGUIClient { +public: + PopupGUIClient( KInstance *inst, const QString &doc ) { + setInstance( inst ); + setXML( doc ); + } +}; + + +void GVImagePart::openContextMenu(const QPoint& pos) { + QString doc = KXMLGUIFactory::readConfigFile( "gvimagepartpopup.rc", true, instance() ); + PopupGUIClient guiClient(instance(), doc); + + KStdAction::saveAs( this, SLOT(saveAs()), guiClient.actionCollection(), "saveAs" ); + + KParts::URLArgs urlArgs; + urlArgs.serviceType = mDocument->mimeType(); + + KParts::BrowserExtension::PopupFlags flags = + KParts::BrowserExtension::ShowNavigationItems + | KParts::BrowserExtension::ShowUp + | KParts::BrowserExtension::ShowReload; + + emit mBrowserExtension->popupMenu(&guiClient, pos, m_url, urlArgs, flags, S_IFREG); +} + + +/***** GVImagePartBrowserExtension *****/ + +GVImagePartBrowserExtension::GVImagePartBrowserExtension(GVImagePart* viewPart, const char* name) + :KParts::BrowserExtension(viewPart, name) { + mGVImagePart = viewPart; + emit enableAction("print", true ); +} + +GVImagePartBrowserExtension::~GVImagePartBrowserExtension() { +} + +void GVImagePartBrowserExtension::print() { + mGVImagePart->print(); +} + +} // namespace diff --git a/src/gvimagepart/gvimagepart.desktop b/src/gvimagepart/gvimagepart.desktop new file mode 100644 index 0000000..97ce129 --- /dev/null +++ b/src/gvimagepart/gvimagepart.desktop @@ -0,0 +1,48 @@ +[Desktop Entry] +Type=Service +Name=Gwenview Image Viewer +Name[bg]=Gwenview - преглед на изображения +Name[br]=Gweler skeudennoù Gwenview +Name[ca]=Visor d'imatges Gwenview +Name[cs]=Prohlížeč obrázků Gwenview +Name[da]=Gwenview billedfremviser +Name[de]=Gwenview Bildbetrachter +Name[el]=Προβολέας εικόνων Gwenview +Name[es]=Visor de imágenes Gwenview +Name[et]=Gwenview pildinäitaja +Name[fa]=مشاهده‌گر تصویر Gwenview +Name[fi]=Gwenview-kuvankatseluohjelma +Name[fr]=Aperçu d'images Gwenview +Name[gl]=Visor de Imaxes Gwenview +Name[hi]=ग्वेन-व्यू छवि प्रदर्शक +Name[hr]=Gwenview preglednik slika +Name[hu]=Gwenview képnézegető +Name[is]=Gwenview myndaskoðari +Name[it]=Visualizzatore di immagini Gwenview +Name[ja]=Gwenview 画像ビューア +Name[ka]=Gwenview სურათების დამთვალიერებელი +Name[ms]=Pelihat imej Gwenview +Name[nds]=Bildkieker Gwenview +Name[nl]=Gwenview Afbeeldingenweergave +Name[pa]=Gwenview ਚਿੱਤਰ ਦਰਸ਼ਕ +Name[pl]=Przeglądarka obrazków Gwenview +Name[pt]=Visualizador de Imagens Gwenview +Name[pt_BR]=Visualizador de Imagens Gwenview +Name[ru]=Gwenview +Name[sk]=Prehliadač obrázkov Gwenview +Name[sl]=Pregledovalnik slik Gwenview +Name[sr]=Прегледач слика Gwenview +Name[sr@Latn]=Pregledač slika Gwenview +Name[sv]=Gwenview bildvisare +Name[ta]=Gwenview பிம்பம் பார்வையாளர் +Name[tg]=Намоишгари тасвири Gwenview +Name[tr]=Gwenview Resim Gösterici +Name[uk]=Переглядач зображень - Gwenview +Name[vi]=Bộ xem ảnh Gwenview +Name[xx]=xxGwenview Image Viewerxx +Name[zh_CN]=Gwenview 图像查看器 +MimeType=image/gif;image/jpeg;image/png;image/x-bmp;image/x-eps;image/x-ico;image/x-krl;image/x-portable-bitmap;image/x-portable-pixmap;image/x-xbm;image/x-xpm +ServiceTypes=KParts/ReadOnlyPart +X-KDE-Library=libgvimagepart +InitialPreference=5 +Icon=gwenview diff --git a/src/gvimagepart/gvimagepart.h b/src/gvimagepart/gvimagepart.h new file mode 100644 index 0000000..d77adc7 --- /dev/null +++ b/src/gvimagepart/gvimagepart.h @@ -0,0 +1,181 @@ +/* +Copyright 2004 Jonathan Riddell + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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 Steet, Fifth Floor, Boston, MA 02111-1307, USA. + +*/ +#ifndef __gvimagepart_h__ +#define __gvimagepart_h__ + +#include +#include +#include + +// Forward declarations +class QFile; +class QPoint; + +class KAboutData; +class KAction; +class KDirLister; +class KFileItem; + +namespace Gwenview { +class ImageView; +class Document; +class ImageLoader; + +class GVImagePart; + +/** + * The browser extension is an attribute of GVImagePart and provides + * some services to Konqueror. All Konqueror KParts have one. + */ +class GVImagePartBrowserExtension: public KParts::BrowserExtension { + Q_OBJECT + +public: + GVImagePartBrowserExtension(GVImagePart* viewPart, const char* name=0L); + ~GVImagePartBrowserExtension(); + +public slots: + void print(); + +private: + GVImagePart* mGVImagePart; + +}; + +/** + * A Read Only KPart to view images using Gwenview + */ +class GVImagePart : public KParts::ReadOnlyPart { + Q_OBJECT +public: + GVImagePart(QWidget*, const char*, QObject*, const char*, const QStringList &); + virtual ~GVImagePart(); + + /** + * Return information about the part + */ + static KAboutData* createAboutData(); + + /** + * Returns m_file + */ + QString filePath(); + + /** + * Print the image being viewed + */ + void print(); + +public slots: + virtual bool openURL(const KURL& url); + +protected slots: + virtual bool openFile() { return false; } + + /** + * Rotates the current image 90 degrees counter clockwise + */ + void rotateLeft(); + + /** + * Rotates the current image 90 degrees clockwise + */ + void rotateRight(); + +protected: + virtual void partActivateEvent(KParts::PartActivateEvent* event); + virtual void guiActivateEvent( KParts::GUIActivateEvent* event); + +private slots: + + void dirListerClear(); + + void dirListerNewItems( const KFileItemList& ); + + void dirListerDeleteItem(KFileItem*); + + void slotSelectNext(); + void slotSelectPrevious(); + + void prefetchDone(); + + void slotLoading(); + void slotLoaded(const KURL& url); + + void openContextMenu(const QPoint&); + + void saveAs(); + + void showJobError(KIO::Job* job); + +private: + + void updateNextPrevious(); + KURL nextURL() const; + KURL previousURL() const; + void saveOriginalAs(); + + /** + * The component's widget + */ + ImageView* mImageView; + + /** + * Holds the image + */ + Document* mDocument; + + /** + * This inherits from KParts::BrowserExtention and supplies + * some extra functionality to Konqueror. + */ + GVImagePartBrowserExtension* mBrowserExtension; + + // for the next/previous actions + KDirLister* mDirLister; + + KAction* mNextImage; + KAction* mPreviousImage; + // alphabetically sorted filenames of images in the picture's directory + QStringList mImagesInDirectory; + + ImageLoader* mPrefetch; + enum LastDirection { DirectionUnknown, DirectionNext, DirectionPrevious }; + LastDirection mLastDirection; // used for prefetching +}; + + +/** + * This simple helper class uploads data to a remote URL asynchronously + */ +class DataUploader : public QObject { + Q_OBJECT +public: + DataUploader(QWidget* dialogParent, const QByteArray& data, const KURL& destURL); + +private slots: + void slotJobFinished(KIO::Job*); + +private: + KTempFile mTempFile; + QWidget* mDialogParent; +}; + +} // namespace +#endif diff --git a/src/gvimagepart/gvimagepart.rc b/src/gvimagepart/gvimagepart.rc new file mode 100644 index 0000000..af4e9e4 --- /dev/null +++ b/src/gvimagepart/gvimagepart.rc @@ -0,0 +1,40 @@ + + + + &File + + + + + + + &View + + + &Colors + + + + + + + + + + + + + + + + +Main Toolbar + + + + + + + + + diff --git a/src/gvimagepart/gvimagepartpopup.rc b/src/gvimagepart/gvimagepartpopup.rc new file mode 100644 index 0000000..a1b7a6d --- /dev/null +++ b/src/gvimagepart/gvimagepartpopup.rc @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/imageutils/Makefile.am b/src/imageutils/Makefile.am new file mode 100644 index 0000000..33c83b3 --- /dev/null +++ b/src/imageutils/Makefile.am @@ -0,0 +1,36 @@ +# QT_CLEAN_NAMESPACE is needed when building with automake, otherwise +# compilation fails in jpegcontent.cpp +AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. $(LIBEXIF_CFLAGS) $(all_includes) \ + -DQT_CLEAN_NAMESPACE +AM_CCASFLAGS = -I$(srcdir) $(GV_ASM_DEFS) + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +noinst_LTLIBRARIES = libgvimageutils.la + +libgvimageutils_la_SOURCES = \ + imageutils.cpp \ + jpegcontent.cpp \ + scale.cpp \ + transupp.c \ + asm_scale.S \ + croppedqimage.cpp + +libgvimageutils_la_LIBADD = $(LIB_KDECORE) $(LIBQT) $(LIBJPEG) $(LIB_EXIV2) + +noinst_HEADERS = \ + orientation.h \ + imageutils.h \ + jpegcontent.h \ + jinclude.h \ + jpegint.h \ + transupp.h \ + jpegerrormanager.h \ + croppedqimage.h + +METASOURCES = AUTO + +check_PROGRAMS = testjpegcontent +testjpegcontent_SOURCES = testjpegcontent.cpp +testjpegcontent_LDADD = $(LIB_KFILE) libgvimageutils.la +testjpegcontent_LDFLAGS = $(all_libraries) diff --git a/src/imageutils/README b/src/imageutils/README new file mode 100644 index 0000000..335d36e --- /dev/null +++ b/src/imageutils/README @@ -0,0 +1,2 @@ +This directory contains image utilities. It contains code from the JPEGLib to +perform lossless transformations and from the ImageMagick library. diff --git a/src/imageutils/asm_scale.S b/src/imageutils/asm_scale.S new file mode 100644 index 0000000..08b43da --- /dev/null +++ b/src/imageutils/asm_scale.S @@ -0,0 +1,810 @@ +#ifdef HAVE_X86_MMX + +#ifdef __EMX__ +/* Due to strange behaviour of as.exe we use this macros */ +/* For all OS/2 coders - please use PGCC to compile this code */ +#define PR_(foo) ___##foo +#define PT_(foo,func) ___##foo,func +#define SIZE(sym) \ + .___end_##sym:; \ + .size ___##sym,.___end_##sym-___##sym; \ + .align 8; +#else +#define PR_(foo) __##foo +#define PT_(foo,func) __##foo,func +#define SIZE(sym) \ + .__end_##sym:; \ + .size __##sym,.__end_##sym-__##sym; \ + .align 8; +#endif + +/*\ +|*| MMX assembly scaling routine for Imlib2 +|*| Written by Willem Monsuwe +\*/ + +.text + .align 8 +.globl PR_(mimageScale_mmx_AARGBA) +/* .type PT_(mimageScale_mmx_AARGBA,@function) */ + + +/*\ Prototype: __mimageScale_mmx_AARGBA(ImlibScaleInfo *isi, DATA32 *dest, +|*| int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow) +\*/ + +#define isi 8(%ebp) +#define dest 12(%ebp) +#define dxx 16(%ebp) +#define dyy 20(%ebp) +#define dx 24(%ebp) +#define dy 28(%ebp) +#define dw 32(%ebp) +#define dh 36(%ebp) +#define dow 40(%ebp) +#define sow 44(%ebp) + +/*\ Local variables that didn't fit in registers \*/ +#define y -4(%ebp) +#define yp -8(%ebp) +#define yap -12(%ebp) +#define xp -16(%ebp) +#define xap -20(%ebp) +#define Cx -24(%ebp) +#define Mx -28(%ebp) +#define Cy -32(%ebp) +#define My -36(%ebp) +#define sow_4 -40(%ebp) + +/*\ When %edx points to ImlibScaleInfo, these are the members \*/ +#define xpoints (%edx) +#define ypoints 4(%edx) +#define xapoints 8(%edx) +#define yapoints 12(%edx) +#define xup_yup 16(%edx) + +PR_(mimageScale_mmx_AARGBA): + pushl %ebp + movl %esp, %ebp + subl $40, %esp + pushl %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + movl isi, %edx + + /*\ Check (dw > 0) && (dh > 0) \*/ + cmpl $0, dw + jle .scale_leave + cmpl $0, dh + jle .scale_leave + + /*\ X-based array pointers point to the end; we're looping up to 0 \*/ + /*\ %edi = dest + dow * dy + dx + dw \*/ + movl dow, %eax + imull dy, %eax + addl dx, %eax + addl dw, %eax + movl dest, %edi + leal (%edi, %eax, 4), %edi + /*\ xp = xpoints + dxx + dw \*/ + movl dxx, %ebx + addl dw, %ebx + movl xpoints, %eax + leal (%eax, %ebx, 4), %eax + movl %eax, xp + /*\ xap = xapoints + dxx + dw \*/ + movl xapoints, %eax + leal (%eax, %ebx, 4), %eax + movl %eax, xap + /*\ y = dh \*/ + movl dh, %eax + movl %eax, y + /*\ yp = ypoints + dyy \*/ + movl dyy, %ebx + movl ypoints, %eax + leal (%eax, %ebx, 4), %eax + movl %eax, yp + /*\ yap = yapoints + dyy \*/ + movl yapoints, %eax + leal (%eax, %ebx, 4), %eax + movl %eax, yap + + pxor %mm7, %mm7 + + /*\ Test xup bit \*/ + movl xup_yup, %eax + sarl $1, %eax + jnc .scale_x_down + +.scale_x_up: + /*\ Test yup bit \*/ + sarl $1, %eax + jnc .scale_x_up_y_down + + +/*\ Scaling up both ways \*/ + +.scale_x_up_y_up: + movl sow, %ebx + +.up_up_loop_y: + + /*\ x = -dw \*/ + movl dw, %ecx + negl %ecx + + /*\ %eax = *yap << 4 \*/ + movl yap, %eax + movl (%eax), %eax + sall $4, %eax + jz .up_up_yap_0 + movd %eax, %mm1 + punpcklwd %mm1, %mm1 + punpckldq %mm1, %mm1 + +.up_up_loop1_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + /*\ %eax = xap[x] << 4 \*/ + movl xap, %eax + movl (%eax, %ecx, 4), %eax + sall $4, %eax + jz .up_up_xap_0 + + /*\ %mm0 = xap[x] << 4 \*/ + movd %eax, %mm0 + punpcklwd %mm0, %mm0 + punpckldq %mm0, %mm0 + + /*\ Load and unpack four pixels in parralel + |*| %mm2 = ptr[0], %mm3 = ptr[1] + |*| %mm4 = ptr[sow], %mm5 = ptr[sow + 1] + \*/ + movq (%esi), %mm2 + movq (%esi, %ebx, 4), %mm4 + movq %mm2, %mm3 + movq %mm4, %mm5 + punpcklbw %mm7, %mm2 + punpcklbw %mm7, %mm4 + punpckhbw %mm7, %mm3 + punpckhbw %mm7, %mm5 + + /*\ X interpolation: r = l + (r - l) * xap \*/ + psubw %mm2, %mm3 + psubw %mm4, %mm5 + psllw $4, %mm3 + psllw $4, %mm5 + pmulhw %mm0, %mm3 + pmulhw %mm0, %mm5 + paddw %mm2, %mm3 + paddw %mm4, %mm5 + /*\ Now %mm3 = I(ptr[0], ptr[1]), %mm5 = I(ptr[sow], ptr[sow + 1]) \*/ + jmp .up_up_common +.up_up_xap_0: + /*\ Load and unpack two pixels + |*| %mm3 = ptr[0], %mm5 = ptr[sow] + \*/ + movd (%esi), %mm3 + movd (%esi, %ebx, 4), %mm5 + punpcklbw %mm7, %mm3 + punpcklbw %mm7, %mm5 +.up_up_common: + /*\ Y interpolation: d = u + (d - u) * yap \*/ + psubw %mm3, %mm5 + psllw $4, %mm5 + pmulhw %mm1, %mm5 + paddw %mm3, %mm5 + packuswb %mm5, %mm5 + movd %mm5, (%edi, %ecx, 4) + + /*\ while (++x) \*/ + incl %ecx + jnz .up_up_loop1_x + jmp .up_up_yap_end +.up_up_yap_0: + +.up_up_loop2_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + /*\ %eax = xap[x] << 4 \*/ + movl xap, %eax + movl (%eax, %ecx, 4), %eax + sall $4, %eax + jz .up_up_0 + + /*\ %mm0 = xap[x] << 4 \*/ + movd %eax, %mm0 + punpcklwd %mm0, %mm0 + punpckldq %mm0, %mm0 + + /*\ Load and unpack two pixels in parralel + |*| %mm2 = ptr[0], %mm3 = ptr[1] + \*/ + movq (%esi), %mm2 + movq %mm2, %mm3 + punpcklbw %mm7, %mm2 + punpckhbw %mm7, %mm3 + + /*\ X interpolation: r = l + (r - l) * xap \*/ + psubw %mm2, %mm3 + psllw $4, %mm3 + pmulhw %mm0, %mm3 + paddw %mm2, %mm3 + packuswb %mm3, %mm3 + movd %mm3, (%edi, %ecx, 4) + jmp .up_up_1 +.up_up_0: + /*\ dptr[x] = *sptr \*/ + movl (%esi), %eax + movl %eax, (%edi, %ecx, 4) +.up_up_1: + incl %ecx + jnz .up_up_loop2_x + +.up_up_yap_end: + /*\ dptr += dow \*/ + movl dow, %eax + leal (%edi, %eax, 4), %edi + /*\ yap++; yp++ \*/ + addl $4, yap + addl $4, yp + /*\ while (y--) \*/ + decl y + jnz .up_up_loop_y + + jmp .scale_leave + + +/*\ Scaling down vertically \*/ + +.scale_x_up_y_down: + /*\ sow_4 = sow * 4 \*/ + movl sow, %eax + sall $2, %eax + movl %eax, sow_4 + +.up_down_loop_y: + + /*\ Setup My and Cy \*/ + movl yap, %eax + movzwl (%eax), %ebx + movl %ebx, My + movzwl 2(%eax), %eax + movl %eax, Cy + + /*\ mm4 = Cy \*/ + movd %eax, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + /*\ mm5 = My \*/ + movd %ebx, %mm5 + punpcklwd %mm5, %mm5 + punpckldq %mm5, %mm5 + + /*\ x = -dw \*/ + movl dw, %ecx + negl %ecx +.up_down_loop_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + movl %esi, %eax + /*\ v = (*p * My) >> 10 \*/ + movd (%eax), %mm0 + punpcklbw %mm7, %mm0 + psllw $6, %mm0 + pmulhw %mm5, %mm0 + + /*\ i = 0x4000 - My \*/ + movl $0x4000, %ebx + subl My, %ebx + jbe 5f + jmp 2f +1: + /*\ p += sow; v += (*p * Cy) >> 10 \*/ + addl sow_4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm0 + + /*\ i -= Cy; while (i > Cy) \*/ + subl Cy, %ebx +2: + cmpl Cy, %ebx + jg 1b + + /*\ mm6 = i \*/ + movd %ebx, %mm6 + punpcklwd %mm6, %mm6 + punpckldq %mm6, %mm6 + + /*\ p += sow; v += (*p * i) >> 10 \*/ + addl sow_4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm0 +5: + /*\ %eax = xap[x] << 5 \*/ + movl xap, %eax + movl (%eax, %ecx, 4), %eax + sall $5, %eax + jz 6f + /*\ mm3 = xap[x] << 5 \*/ + movd %eax, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + + /*\ p + 1 \*/ + movl %esi, %eax + addl $4, %eax + /*\ vv = (*p * My) >> 10 \*/ + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $6, %mm2 + pmulhw %mm5, %mm2 + + /*\ i = 0x4000 - My \*/ + movl $0x4000, %ebx + subl My, %ebx + jbe 5f + jmp 2f +1: + /*\ p += sow; vv += (*p * Cy) >> 10 \*/ + addl sow_4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm2 + + /*\ i -= Cy; while (i > Cy) \*/ + subl Cy, %ebx +2: + cmpl Cy, %ebx + jg 1b + + /*\ p += sow; v += (*p * i) >> 10 \*/ + addl sow_4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm2 +5: + /*\ v = v + (vv - v) * xap \*/ + psubw %mm0, %mm2 + psllw $3, %mm2 + pmulhw %mm3, %mm2 + paddw %mm2, %mm0 +6: + /*\ dest[x] = v >> 4 \*/ + psrlw $4, %mm0 + packuswb %mm0, %mm0 + movd %mm0, (%edi, %ecx, 4) + + /*\ while (++x) \*/ + incl %ecx + jnz .up_down_loop_x + + /*\ dptr += dow \*/ + movl dow, %eax + leal (%edi, %eax, 4), %edi + /*\ yap++; yp++ \*/ + addl $4, yap + addl $4, yp + /*\ while (y--) \*/ + decl y + jnz .up_down_loop_y + + jmp .scale_leave + +.scale_x_down: + /*\ Test yup bit \*/ + sarl $1, %eax + jnc .scale_x_down_y_down + + +/*\ Scaling down horizontally \*/ + +.scale_x_down_y_up: + /*\ sow_4 = sow * 4 \*/ + movl sow, %eax + sall $2, %eax + movl %eax, sow_4 + +.down_up_loop_y: + + /*\ %eax = *yap << 5 \*/ + movl yap, %eax + movl (%eax), %eax + sall $5, %eax + /*\ mm3 = *yap << 5 \*/ + movd %eax, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + + /*\ x = -dw \*/ + movl dw, %ecx + negl %ecx +.down_up_loop_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + /*\ Setup Mx and Cx \*/ + movl xap, %eax + movzwl (%eax, %ecx, 4), %ebx + movl %ebx, Mx + movzwl 2(%eax, %ecx, 4), %eax + movl %eax, Cx + + /*\ mm4 = Cx \*/ + movd %eax, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + /*\ mm5 = Mx \*/ + movd %ebx, %mm5 + punpcklwd %mm5, %mm5 + punpckldq %mm5, %mm5 + + movl %esi, %eax + /*\ v = (*p * Mx) >> 10 \*/ + movd (%eax), %mm0 + punpcklbw %mm7, %mm0 + psllw $6, %mm0 + pmulhw %mm5, %mm0 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ p += sow; v += (*p * Cx) >> 10 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm0 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ mm6 = i \*/ + movd %ebx, %mm6 + punpcklwd %mm6, %mm6 + punpckldq %mm6, %mm6 + + /*\ p += sow; v += (*p * i) >> 10 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm0 +5: + movd %mm3, %eax + testl %eax, %eax + jz 6f + /*\ p + sow \*/ + movl %esi, %eax + addl sow_4, %eax + /*\ vv = (*p * Mx) >> 10 \*/ + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $6, %mm2 + pmulhw %mm5, %mm2 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ p += sow; vv += (*p * Cx) >> 10 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm2 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ p += sow; v += (*p * i) >> 10 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm2 +5: + /*\ v = v + (vv - v) * yap \*/ + psubw %mm0, %mm2 + psllw $3, %mm2 + pmulhw %mm3, %mm2 + paddw %mm2, %mm0 +6: + /*\ dest[x] = v >> 4 \*/ + psrlw $4, %mm0 + packuswb %mm0, %mm0 + movd %mm0, (%edi, %ecx, 4) + + /*\ while (++x) \*/ + incl %ecx + jnz .down_up_loop_x + + /*\ dptr += dow \*/ + movl dow, %eax + leal (%edi, %eax, 4), %edi + /*\ yap++; yp++ \*/ + addl $4, yap + addl $4, yp + /*\ while (y--) \*/ + decl y + jnz .down_up_loop_y + + jmp .scale_leave + + +/*\ Scaling down both ways \*/ + +.scale_x_down_y_down: + /*\ sow_4 = sow * 4 \*/ + movl sow, %eax + sall $2, %eax + movl %eax, sow_4 + +.down_down_loop_y: + + /*\ Setup My and Cy \*/ + movl yap, %eax + movzwl (%eax), %ebx + movl %ebx, My + movzwl 2(%eax), %eax + movl %eax, Cy + + /*\ x = -dw \*/ + movl dw, %ecx + negl %ecx +.down_down_loop_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + /*\ Setup Mx and Cx \*/ + movl xap, %eax + movzwl (%eax, %ecx, 4), %ebx + movl %ebx, Mx + movzwl 2(%eax, %ecx, 4), %eax + movl %eax, Cx + + /*\ mm3 = Cx \*/ + movd %eax, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + /*\ mm5 = Mx \*/ + movd %ebx, %mm5 + punpcklwd %mm5, %mm5 + punpckldq %mm5, %mm5 + + /*\ p = sptr; v = (*p * Mx) >> 9 \*/ + movl %esi, %eax + movd (%eax), %mm0 + punpcklbw %mm7, %mm0 + psllw $7, %mm0 + pmulhw %mm5, %mm0 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ v += (*++p * Cx) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $7, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm0 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ mm6 = i \*/ + movd %ebx, %mm6 + punpcklwd %mm6, %mm6 + punpckldq %mm6, %mm6 + + /*\ v += (*++p * i) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $7, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm0 +5: + /*\ v *= My \*/ + movd My, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + psllw $2, %mm0 + pmulhw %mm4, %mm0 + + /*\ j = 0x4000 - My \*/ + movl $0x4000, %edx + subl My, %edx + jbe 6f + jmp 4f +3: + /*\ sptr += sow; p = sptr \*/ + addl sow_4, %esi + movl %esi, %eax + /*\ vx = (*p * Mx) >> 9 \*/ + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $7, %mm1 + pmulhw %mm5, %mm1 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ vx += (*++p * Cx) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $7, %mm2 + pmulhw %mm3, %mm2 + paddw %mm2, %mm1 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ vx += (*++p * i) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $7, %mm2 + pmulhw %mm6, %mm2 + paddw %mm2, %mm1 +5: + /*\ v += (vx * Cy) >> 14 \*/ + movd Cy, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + psllw $2, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm0 + + /*\ j -= Cy; while (j > Cy) \*/ + subl Cy, %edx +4: + cmpl Cy, %edx + jg 3b + + /*\ sptr += sow; p = sptr \*/ + addl sow_4, %esi + movl %esi, %eax + /*\ vx = (*p * Mx) >> 9 \*/ + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $7, %mm1 + pmulhw %mm5, %mm1 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ vx += (*++p * Cx) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $7, %mm2 + pmulhw %mm3, %mm2 + paddw %mm2, %mm1 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ vx += (*++p * i) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $7, %mm2 + pmulhw %mm6, %mm2 + paddw %mm2, %mm1 +5: + /*\ v += (vx * j) >> 14 \*/ + movd %edx, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + psllw $2, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm0 +6: + /*\ dptr[x] = mm0 >> 5 \*/ + psrlw $5, %mm0 + packuswb %mm0, %mm0 + movd %mm0, (%edi, %ecx, 4) + + /*\ while (++x) \*/ + incl %ecx + jnz .down_down_loop_x + + /*\ dptr += dow \*/ + movl dow, %eax + leal (%edi, %eax, 4), %edi + /*\ yap++; yp++ \*/ + addl $4, yap + addl $4, yp + /*\ while (y--) \*/ + decl y + jnz .down_down_loop_y + + jmp .scale_leave + +.scale_leave: + emms + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + movl %ebp, %esp + popl %ebp + ret + +SIZE(mimageScale_mmx_AARGBA) + +#endif + +.section .note.GNU-stack,"",%progbits diff --git a/src/imageutils/croppedqimage.cpp b/src/imageutils/croppedqimage.cpp new file mode 100644 index 0000000..5ed2aab --- /dev/null +++ b/src/imageutils/croppedqimage.cpp @@ -0,0 +1,77 @@ +/* + + Copyright (C) 2005 Lubos Lunak + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "croppedqimage.h" + +namespace ImageUtils +{ + +// This class is used in ImageView::performPaint(). Just using QImage::copy( QRect ) +// takes a significant time with very large images. So instead of copying the image data +// just create CroppedQImage which fakes a subimage by manipulating its scanline pointers. +// That will of course break if something doesn't use scanlines but accesses the image +// data directly, QImage::copy() being the most notable case. There are two ways +// to handle that: 1) It is possible to manually call normalize() which will make +// CroppedQImage copy the image data and own it, just like proper QImage. 2) CroppedQImage +// has as a data member also QImage holding the original image. This ensures that all +// the original image data are still available for the whole lifetime of CroppedQImage. + +CroppedQImage::CroppedQImage( const QImage& im, const QRect& rect ) + : QImage( rect.size(), im.depth(), im.numColors(), im.bitOrder()) + , orig( im ) + { + if( im.isNull()) + return; + memcpy( colorTable(), im.colorTable(), im.numColors() * sizeof( QRgb )); + setAlphaBuffer( im.hasAlphaBuffer()); + setDotsPerMeterX( im.dotsPerMeterX()); + setDotsPerMeterY( im.dotsPerMeterY()); + //data->offset = im.offset(); + // make scanlines point to right places in the original QImage + for( int i = 0; + i < height(); + ++i ) + jumpTable()[ i ] = im.scanLine( rect.y() + i ) + rect.x() * ( depth() / 8 ); + } + +CroppedQImage& CroppedQImage::operator= ( const QImage& im ) + { + QImage::operator=( im ); + return *this; + } + +void CroppedQImage::normalize() + { + // is it a normal QImage with its own data? + uchar* firstdata = ( uchar* )( jumpTable() + height()); + if( scanLine( 0 ) == firstdata ) + return; + // copy the image data to our own data and make scanlines point properly there + for( int i = 0; + i < height(); + ++i ) + { + uchar* oldline = scanLine( i ); + jumpTable()[ i ] = firstdata + i * bytesPerLine(); + memcpy( scanLine( i ), oldline, bytesPerLine()); + } + } + +} // namespace diff --git a/src/imageutils/croppedqimage.h b/src/imageutils/croppedqimage.h new file mode 100644 index 0000000..4d93840 --- /dev/null +++ b/src/imageutils/croppedqimage.h @@ -0,0 +1,42 @@ +/* + + Copyright (C) 2005 Lubos Lunak + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef CROPPED_QIMAGE_H +#define CROPPED_QIMAGE_H + +#include + +namespace ImageUtils +{ + +class CroppedQImage + : public QImage + { + public: + CroppedQImage( const QImage& im, const QRect& rect ); + CroppedQImage& operator= ( const QImage& im ); + void normalize(); + private: + QImage orig; + }; + +} // namespace + +#endif diff --git a/src/imageutils/imageutils.cpp b/src/imageutils/imageutils.cpp new file mode 100644 index 0000000..c9d04ca --- /dev/null +++ b/src/imageutils/imageutils.cpp @@ -0,0 +1,211 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include + +// Qt +#include +#include + +// KDE +#include +#include +#include + +// Local +#include "imageutils/orientation.h" + +namespace ImageUtils { + + +QWMatrix transformMatrix(Orientation orientation) { + QWMatrix matrix; + switch (orientation) { + case NOT_AVAILABLE: + case NORMAL: + break; + + case HFLIP: + matrix.scale(-1,1); + break; + + case ROT_180: + matrix.rotate(180); + break; + + case VFLIP: + matrix.scale(1,-1); + break; + + case TRANSPOSE: + matrix.scale(-1,1); + matrix.rotate(90); + break; + + case ROT_90: + matrix.rotate(90); + break; + + case TRANSVERSE: + matrix.scale(1,-1); + matrix.rotate(90); + break; + + case ROT_270: + matrix.rotate(270); + break; + } + + return matrix; +} + + +QImage transform(const QImage& img, Orientation orientation) { + if (orientation != NOT_AVAILABLE && orientation != NORMAL) { + return img.xForm(transformMatrix(orientation)); + } else { + return img; + } +} + + +inline +int changeBrightness( int value, int brightness ) + { + return KCLAMP( value + brightness * 255 / 100, 0, 255 ); + } + +inline +int changeContrast( int value, int contrast ) + { + return KCLAMP((( value - 127 ) * contrast / 100 ) + 127, 0, 255 ); + } + +inline +int changeGamma( int value, int gamma ) + { + return KCLAMP( int( pow( value / 255.0, 100.0 / gamma ) * 255 ), 0, 255 ); + } + +inline +int changeUsingTable( int value, const int table[] ) + { + return table[ value ]; + } + +/* + Applies either brightness, contrast or gamma conversion on the image. + If the image is not truecolor, the color table is changed. If it is + truecolor, every pixel has to be changed. In order to make it as fast + as possible, alpha value is converted only if necessary. Additionally, + since color components (red/green/blue/alpha) can have only 256 values + but images usually have many pixels, a conversion table is first + created for every color component value, and pixels are converted + using this table. +*/ + +template< int operation( int, int ) > +static +QImage changeImage( const QImage& image, int value ) + { + QImage im = image; + im.detach(); + if( im.numColors() == 0 ) /* truecolor */ + { + if( im.depth() != 32 ) /* just in case */ + im = im.convertDepth( 32 ); + int table[ 256 ]; + for( int i = 0; + i < 256; + ++i ) + table[ i ] = operation( i, value ); + if( im.hasAlphaBuffer()) + { + for( int y = 0; + y < im.height(); + ++y ) + { + QRgb* line = reinterpret_cast< QRgb* >( im.scanLine( y )); + for( int x = 0; + x < im.width(); + ++x ) + line[ x ] = qRgba( changeUsingTable( qRed( line[ x ] ), table ), + changeUsingTable( qGreen( line[ x ] ), table ), + changeUsingTable( qBlue( line[ x ] ), table ), + changeUsingTable( qAlpha( line[ x ] ), table )); + } + } + else + { + for( int y = 0; + y < im.height(); + ++y ) + { + QRgb* line = reinterpret_cast< QRgb* >( im.scanLine( y )); + for( int x = 0; + x < im.width(); + ++x ) + line[ x ] = qRgb( changeUsingTable( qRed( line[ x ] ), table ), + changeUsingTable( qGreen( line[ x ] ), table ), + changeUsingTable( qBlue( line[ x ] ), table )); + } + } + } + else + { + QRgb* colors = im.colorTable(); + for( int i = 0; + i < im.numColors(); + ++i ) + colors[ i ] = qRgb( operation( qRed( colors[ i ] ), value ), + operation( qGreen( colors[ i ] ), value ), + operation( qBlue( colors[ i ] ), value )); + } + return im; + } + + +// brightness is multiplied by 100 in order to avoid floating point numbers +QImage changeBrightness( const QImage& image, int brightness ) + { + if( brightness == 0 ) // no change + return image; + return changeImage< changeBrightness >( image, brightness ); + } + + +// contrast is multiplied by 100 in order to avoid floating point numbers +QImage changeContrast( const QImage& image, int contrast ) + { + if( contrast == 100 ) // no change + return image; + return changeImage< changeContrast >( image, contrast ); + } + +// gamma is multiplied by 100 in order to avoid floating point numbers +QImage changeGamma( const QImage& image, int gamma ) + { + if( gamma == 100 ) // no change + return image; + return changeImage< changeGamma >( image, gamma ); + } + +} // Namespace + diff --git a/src/imageutils/imageutils.h b/src/imageutils/imageutils.h new file mode 100644 index 0000000..62b757c --- /dev/null +++ b/src/imageutils/imageutils.h @@ -0,0 +1,49 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef IMAGEUTILS_H +#define IMAGEUTILS_H + +// Qt +#include + +// Local +#include "imageutils/orientation.h" + +namespace ImageUtils { + enum SmoothAlgorithm { SMOOTH_NONE, SMOOTH_FAST, SMOOTH_NORMAL, SMOOTH_BEST }; + + QImage scale(const QImage& image, int width, int height, + SmoothAlgorithm alg, QImage::ScaleMode mode = QImage::ScaleFree, double blur = 1.0); + + int extraScalePixels( SmoothAlgorithm alg, double zoom, double blur = 1.0 ); + + QImage transform(const QImage& img, Orientation orientation); + + QImage changeBrightness( const QImage& image, int brightness ); + + QImage changeContrast( const QImage& image, int contrast ); + + QImage changeGamma( const QImage& image, int gamma ); + + QWMatrix transformMatrix(Orientation orientation); +} + +#endif diff --git a/src/imageutils/jinclude.h b/src/imageutils/jinclude.h new file mode 100644 index 0000000..0a4f151 --- /dev/null +++ b/src/imageutils/jinclude.h @@ -0,0 +1,91 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/src/imageutils/jpegcontent.cpp b/src/imageutils/jpegcontent.cpp new file mode 100644 index 0000000..b44b14d --- /dev/null +++ b/src/imageutils/jpegcontent.cpp @@ -0,0 +1,666 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// System +#include +#include +#include +#include +extern "C" { +#include +#include "transupp.h" +} + +// Qt +#include +#include +#include +#include +#include + +// KDE +#include + +// Exiv2 +#include +#include + +// Local +#include "imageutils/imageutils.h" +#include "imageutils/jpegcontent.h" +#include "imageutils/jpegerrormanager.h" + +namespace ImageUtils { + +const int INMEM_DST_DELTA=4096; + + +//------------------------------------------ +// +// In-memory data source manager for libjpeg +// +//------------------------------------------ +struct inmem_src_mgr : public jpeg_source_mgr { + QByteArray* mInput; +}; + +void inmem_init_source(j_decompress_ptr cinfo) { + inmem_src_mgr* src=(inmem_src_mgr*)(cinfo->src); + src->next_input_byte=(const JOCTET*)( src->mInput->data() ); + src->bytes_in_buffer=src->mInput->size(); +} + +/** + * If this function is called, it means the JPEG file is broken. We feed the + * decoder with fake EOI has specified in the libjpeg documentation. + */ +int inmem_fill_input_buffer(j_decompress_ptr cinfo) { + static JOCTET fakeEOI[2]={ JOCTET(0xFF), JOCTET(JPEG_EOI)}; + kdWarning() << k_funcinfo << " Image is incomplete" << endl; + cinfo->src->next_input_byte=fakeEOI; + cinfo->src->bytes_in_buffer=2; + return true; +} + +void inmem_skip_input_data(j_decompress_ptr cinfo, long num_bytes) { + if (num_bytes<=0) return; + Q_ASSERT(num_bytes>=long(cinfo->src->bytes_in_buffer)); + cinfo->src->next_input_byte+=num_bytes; + cinfo->src->bytes_in_buffer-=num_bytes; +} + +void inmem_term_source(j_decompress_ptr /*cinfo*/) { +} + + +//----------------------------------------------- +// +// In-memory data destination manager for libjpeg +// +//----------------------------------------------- +struct inmem_dest_mgr : public jpeg_destination_mgr { + QByteArray* mOutput; + + void dump() { + kdDebug() << "dest_mgr:\n"; + kdDebug() << "- next_output_byte: " << next_output_byte << endl; + kdDebug() << "- free_in_buffer: " << free_in_buffer << endl; + kdDebug() << "- output size: " << mOutput->size() << endl; + } +}; + +void inmem_init_destination(j_compress_ptr cinfo) { + inmem_dest_mgr* dest=(inmem_dest_mgr*)(cinfo->dest); + if (dest->mOutput->size()==0) { + bool result=dest->mOutput->resize(INMEM_DST_DELTA); + Q_ASSERT(result); + } + dest->free_in_buffer=dest->mOutput->size(); + dest->next_output_byte=(JOCTET*)(dest->mOutput->data() ); +} + +int inmem_empty_output_buffer(j_compress_ptr cinfo) { + inmem_dest_mgr* dest=(inmem_dest_mgr*)(cinfo->dest); + bool result=dest->mOutput->resize(dest->mOutput->size() + INMEM_DST_DELTA); + Q_ASSERT(result); + dest->next_output_byte=(JOCTET*)( dest->mOutput->data() + dest->mOutput->size() - INMEM_DST_DELTA ); + dest->free_in_buffer=INMEM_DST_DELTA; + + return true; +} + +void inmem_term_destination(j_compress_ptr cinfo) { + inmem_dest_mgr* dest=(inmem_dest_mgr*)(cinfo->dest); + int finalSize=dest->next_output_byte - (JOCTET*)(dest->mOutput->data()); + Q_ASSERT(finalSize>=0); + dest->mOutput->resize(finalSize); +} + + +//--------------------- +// +// JPEGContent::Private +// +//--------------------- +struct JPEGContent::Private { + QByteArray mRawData; + QSize mSize; + QString mComment; + QString mAperture; + QString mExposureTime; + QString mFocalLength; + QString mIso; + + bool mPendingTransformation; + QWMatrix mTransformMatrix; + Exiv2::ExifData mExifData; + + Private() { + mPendingTransformation = false; + } + + void setupInmemSource(j_decompress_ptr cinfo) { + Q_ASSERT(!cinfo->src); + inmem_src_mgr* src = (inmem_src_mgr*) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(inmem_src_mgr)); + cinfo->src=(struct jpeg_source_mgr*)(src); + + src->init_source=inmem_init_source; + src->fill_input_buffer=inmem_fill_input_buffer; + src->skip_input_data=inmem_skip_input_data; + src->resync_to_restart=jpeg_resync_to_restart; + src->term_source=inmem_term_source; + + src->mInput=&mRawData; + } + + + void setupInmemDestination(j_compress_ptr cinfo, QByteArray* outputData) { + Q_ASSERT(!cinfo->dest); + inmem_dest_mgr* dest = (inmem_dest_mgr*) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(inmem_dest_mgr)); + cinfo->dest=(struct jpeg_destination_mgr*)(dest); + + dest->init_destination=inmem_init_destination; + dest->empty_output_buffer=inmem_empty_output_buffer; + dest->term_destination=inmem_term_destination; + + dest->mOutput=outputData; + } + bool readSize() { + struct jpeg_decompress_struct srcinfo; + jpeg_saved_marker_ptr mark; + + // Init JPEG structs + JPEGErrorManager errorManager; + + // Initialize the JPEG decompression object + srcinfo.err = &errorManager; + jpeg_create_decompress(&srcinfo); + if (setjmp(errorManager.jmp_buffer)) { + kdError() << k_funcinfo << "libjpeg fatal error\n"; + return false; + } + + // Specify data source for decompression + setupInmemSource(&srcinfo); + + // Read the header + jcopy_markers_setup(&srcinfo, JCOPYOPT_ALL); + int result=jpeg_read_header(&srcinfo, true); + if (result!=JPEG_HEADER_OK) { + kdError() << "Could not read jpeg header\n"; + jpeg_destroy_decompress(&srcinfo); + return false; + } + mSize=QSize(srcinfo.image_width, srcinfo.image_height); + + jpeg_destroy_decompress(&srcinfo); + return true; + } +}; + + +//------------ +// +// JPEGContent +// +//------------ +JPEGContent::JPEGContent() { + d=new JPEGContent::Private(); +} + + +JPEGContent::~JPEGContent() { + delete d; +} + + +bool JPEGContent::load(const QString& path) { + QFile file(path); + if (!file.open(IO_ReadOnly)) { + kdError() << "Could not open '" << path << "' for reading\n"; + return false; + } + return loadFromData(file.readAll()); +} + + +bool JPEGContent::loadFromData(const QByteArray& data) { + d->mPendingTransformation = false; + d->mTransformMatrix.reset(); + + d->mRawData = data; + if (d->mRawData.size()==0) { + kdError() << "No data\n"; + return false; + } + + if (!d->readSize()) return false; + + Exiv2::Image::AutoPtr image; + try { + image = Exiv2::ImageFactory::open((unsigned char*)data.data(), data.size()); + image->readMetadata(); + } catch (Exiv2::Error&) { + kdError() << "Could not load image with Exiv2\n"; + return false; + } + + d->mExifData = image->exifData(); + d->mComment = QString::fromUtf8( image->comment().c_str() ); + + d->mAperture=aperture(); + d->mExposureTime=exposureTime(); + d->mIso=iso(); + d->mFocalLength=iso(); + + // Adjust the size according to the orientation + switch (orientation()) { + case TRANSPOSE: + case ROT_90: + case TRANSVERSE: + case ROT_270: + d->mSize.transpose(); + break; + default: + break; + } + + return true; +} + + +Orientation JPEGContent::orientation() const { + Exiv2::ExifKey key("Exif.Image.Orientation"); + Exiv2::ExifData::iterator it = d->mExifData.findKey(key); + if (it == d->mExifData.end()) { + return NOT_AVAILABLE; + } + return Orientation( it->toLong() ); +} + + +int JPEGContent::dotsPerMeterX() const { + return dotsPerMeter("XResolution"); +} + + +int JPEGContent::dotsPerMeterY() const { + return dotsPerMeter("YResolution"); +} + + +int JPEGContent::dotsPerMeter(const QString& keyName) const { + Exiv2::ExifKey keyResUnit("Exif.Image.ResolutionUnit"); + Exiv2::ExifData::iterator it = d->mExifData.findKey(keyResUnit); + if (it == d->mExifData.end()) { + return 0; + } + int res = it->toLong(); + QString keyVal = "Exif.Image." + keyName; + Exiv2::ExifKey keyResolution(keyVal.ascii()); + it = d->mExifData.findKey(keyResolution); + if (it == d->mExifData.end()) { + return 0; + } + // The unit for measuring XResolution and YResolution. The same unit is used for both XResolution and YResolution. + // If the image resolution in unknown, 2 (inches) is designated. + // Default = 2 + // 2 = inches + // 3 = centimeters + // Other = reserved + const float INCHESPERMETER = (100. / 2.54); + Exiv2::Rational r = it->toRational(); + if (r.second == 0) { + // a rational with 0 as second will make hang toLong() conversion + r.second = 1; + } + switch (res) { + case 3: // dots per cm + return int(float(r.first) * 100 / float(r.second)); + default: // dots per inch + return int(float(r.first) * INCHESPERMETER / float(r.second)); + } + + return 0; +} + + +void JPEGContent::resetOrientation() { + Exiv2::ExifKey key("Exif.Image.Orientation"); + Exiv2::ExifData::iterator it = d->mExifData.findKey(key); + if (it == d->mExifData.end()) { + return; + } + + *it = uint16_t(ImageUtils::NORMAL); +} + + +QSize JPEGContent::size() const { + return d->mSize; +} + + +QString JPEGContent::comment() const { + return d->mComment; +} + +QString JPEGContent::getExifInformation(const QString exifkey) const { + QString ret; + + Exiv2::ExifKey key(exifkey.latin1()); + Exiv2::ExifData::iterator it = d->mExifData.findKey(key); + + if (it != d->mExifData.end()) { + std::ostringstream outputString; + outputString << *it; + ret=QString(outputString.str().c_str()); + } + else { + ret="n/a"; + } + return ret; +} + +QString JPEGContent::aperture() const { + d->mAperture=getExifInformation("Exif.Photo.FNumber"); + return d->mAperture; +} + +QString JPEGContent::exposureTime() const { + d->mExposureTime=getExifInformation("Exif.Photo.ExposureTime"); + return d->mExposureTime; +} + +QString JPEGContent::iso() const { + d->mIso=getExifInformation("Exif.Photo.ISOSpeedRatings"); + return d->mIso; +} + +QString JPEGContent::focalLength() const { + d->mFocalLength=getExifInformation("Exif.Photo.FocalLength"); + return d->mFocalLength; +} + +void JPEGContent::setComment(const QString& comment) { + d->mComment = comment; +} + +static QWMatrix createRotMatrix(int angle) { + QWMatrix matrix; + matrix.rotate(angle); + return matrix; +} + + +static QWMatrix createScaleMatrix(int dx, int dy) { + QWMatrix matrix; + matrix.scale(dx, dy); + return matrix; +} + + + +struct OrientationInfo { + OrientationInfo() {} + OrientationInfo(Orientation o, QWMatrix m, JXFORM_CODE j) + : orientation(o), matrix(m), jxform(j) {} + + Orientation orientation; + QWMatrix matrix; + JXFORM_CODE jxform; +}; +typedef QValueList OrientationInfoList; + +static const OrientationInfoList& orientationInfoList() { + static OrientationInfoList list; + if (list.size() == 0) { + QWMatrix rot90 = createRotMatrix(90); + QWMatrix hflip = createScaleMatrix(-1, 1); + QWMatrix vflip = createScaleMatrix(1, -1); + + list + << OrientationInfo(NOT_AVAILABLE, QWMatrix(), JXFORM_NONE) + << OrientationInfo(NORMAL, QWMatrix(), JXFORM_NONE) + << OrientationInfo(HFLIP, hflip, JXFORM_FLIP_H) + << OrientationInfo(ROT_180, createRotMatrix(180), JXFORM_ROT_180) + << OrientationInfo(VFLIP, vflip, JXFORM_FLIP_V) + << OrientationInfo(TRANSPOSE, hflip * rot90, JXFORM_TRANSPOSE) + << OrientationInfo(ROT_90, rot90, JXFORM_ROT_90) + << OrientationInfo(TRANSVERSE, vflip * rot90, JXFORM_TRANSVERSE) + << OrientationInfo(ROT_270, createRotMatrix(270), JXFORM_ROT_270) + ; + } + return list; +} + + +void JPEGContent::transform(Orientation orientation) { + if (orientation != NOT_AVAILABLE && orientation != NORMAL) { + d->mPendingTransformation = true; + OrientationInfoList::ConstIterator it(orientationInfoList().begin()), end(orientationInfoList().end()); + for (; it!=end; ++it) { + if ( (*it).orientation == orientation ) { + d->mTransformMatrix = (*it).matrix * d->mTransformMatrix; + break; + } + } + if (it == end) { + kdWarning() << k_funcinfo << "Could not find matrix for orientation\n"; + } + } +} + + +#if 0 +static void dumpMatrix(const QWMatrix& matrix) { + kdDebug() << "matrix | " << matrix.m11() << ", " << matrix.m12() << " |\n"; + kdDebug() << " | " << matrix.m21() << ", " << matrix.m22() << " |\n"; + kdDebug() << " ( " << matrix.dx() << ", " << matrix.dy() << " )\n"; +} +#endif + + +static bool matricesAreSame(const QWMatrix& m1, const QWMatrix& m2, double tolerance) { + return fabs( m1.m11() - m2.m11() ) < tolerance + && fabs( m1.m12() - m2.m12() ) < tolerance + && fabs( m1.m21() - m2.m21() ) < tolerance + && fabs( m1.m22() - m2.m22() ) < tolerance + && fabs( m1.dx() - m2.dx() ) < tolerance + && fabs( m1.dy() - m2.dy() ) < tolerance; +} + + +static JXFORM_CODE findJxform(const QWMatrix& matrix) { + OrientationInfoList::ConstIterator it(orientationInfoList().begin()), end(orientationInfoList().end()); + for (; it!=end; ++it) { + if ( matricesAreSame( (*it).matrix, matrix, 0.001) ) { + return (*it).jxform; + } + } + kdWarning() << "findJxform: failed\n"; + return JXFORM_NONE; +} + + +void JPEGContent::applyPendingTransformation() { + if (d->mRawData.size()==0) { + kdError() << "No data loaded\n"; + return; + } + + // The following code is inspired by jpegtran.c from the libjpeg + + // Init JPEG structs + struct jpeg_decompress_struct srcinfo; + struct jpeg_compress_struct dstinfo; + jvirt_barray_ptr * src_coef_arrays; + jvirt_barray_ptr * dst_coef_arrays; + + // Initialize the JPEG decompression object + JPEGErrorManager srcErrorManager; + srcinfo.err = &srcErrorManager; + jpeg_create_decompress(&srcinfo); + if (setjmp(srcErrorManager.jmp_buffer)) { + kdError() << k_funcinfo << "libjpeg error in src\n"; + return; + } + + // Initialize the JPEG compression object + JPEGErrorManager dstErrorManager; + dstinfo.err = &dstErrorManager; + jpeg_create_compress(&dstinfo); + if (setjmp(dstErrorManager.jmp_buffer)) { + kdError() << k_funcinfo << "libjpeg error in dst\n"; + return; + } + + // Specify data source for decompression + d->setupInmemSource(&srcinfo); + + // Enable saving of extra markers that we want to copy + jcopy_markers_setup(&srcinfo, JCOPYOPT_ALL); + + (void) jpeg_read_header(&srcinfo, TRUE); + + // Init transformation + jpeg_transform_info transformoption; + transformoption.transform = findJxform(d->mTransformMatrix); + transformoption.force_grayscale = false; + transformoption.trim = false; + jtransform_request_workspace(&srcinfo, &transformoption); + + /* Read source file as DCT coefficients */ + src_coef_arrays = jpeg_read_coefficients(&srcinfo); + + /* Initialize destination compression parameters from source values */ + jpeg_copy_critical_parameters(&srcinfo, &dstinfo); + + /* Adjust destination parameters if required by transform options; + * also find out which set of coefficient arrays will hold the output. + */ + dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, + src_coef_arrays, + &transformoption); + + /* Specify data destination for compression */ + QByteArray output; + output.resize(d->mRawData.size()); + d->setupInmemDestination(&dstinfo, &output); + + /* Start compressor (note no image data is actually written here) */ + jpeg_write_coefficients(&dstinfo, dst_coef_arrays); + + /* Copy to the output file any extra markers that we want to preserve */ + jcopy_markers_execute(&srcinfo, &dstinfo, JCOPYOPT_ALL); + + /* Execute image transformation, if any */ + jtransform_execute_transformation(&srcinfo, &dstinfo, + src_coef_arrays, + &transformoption); + + /* Finish compression and release memory */ + jpeg_finish_compress(&dstinfo); + jpeg_destroy_compress(&dstinfo); + (void) jpeg_finish_decompress(&srcinfo); + jpeg_destroy_decompress(&srcinfo); + + // Set rawData to our new JPEG + d->mRawData = output; +} + + +QImage JPEGContent::thumbnail() const { + QImage image; + if (!d->mExifData.empty()) { + Exiv2::DataBuf thumbnail = d->mExifData.copyThumbnail(); + image.loadFromData(thumbnail.pData_, thumbnail.size_); + } + return image; +} + + +void JPEGContent::setThumbnail(const QImage& thumbnail) { + if (d->mExifData.empty()) { + return; + } + + QByteArray array; + QBuffer buffer(array); + buffer.open(IO_WriteOnly); + QImageIO iio(&buffer, "JPEG"); + iio.setImage(thumbnail); + if (!iio.write()) { + kdError() << "Could not write thumbnail\n"; + return; + } + + d->mExifData.setJpegThumbnail((unsigned char*)array.data(), array.size()); +} + + +bool JPEGContent::save(const QString& path) { + QFile file(path); + if (!file.open(IO_WriteOnly)) { + kdError() << "Could not open '" << path << "' for writing\n"; + return false; + } + + return save(&file); +} + + +bool JPEGContent::save(QFile* file) { + if (d->mRawData.size()==0) { + kdError() << "No data to store in '" << file->name() << "'\n"; + return false; + } + + if (d->mPendingTransformation) { + applyPendingTransformation(); + d->mPendingTransformation = false; + } + + Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((unsigned char*)d->mRawData.data(), d->mRawData.size()); + + // Store Exif info + image->setExifData(d->mExifData); + image->setComment(d->mComment.utf8().data()); + image->writeMetadata(); + + // Update mRawData + Exiv2::BasicIo& io = image->io(); + d->mRawData.resize(io.size()); + io.read((unsigned char*)d->mRawData.data(), io.size()); + + QDataStream stream(file); + stream.writeRawBytes(d->mRawData.data(), d->mRawData.size()); + + // Make sure we are up to date + loadFromData(d->mRawData); + return true; +} + + +} // namespace diff --git a/src/imageutils/jpegcontent.h b/src/imageutils/jpegcontent.h new file mode 100644 index 0000000..40af44d --- /dev/null +++ b/src/imageutils/jpegcontent.h @@ -0,0 +1,86 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef JPEGCONTENT_H +#define JPEGCONTENT_H + +// Qt +#include + +// Local +#include + +#include "../gvcore/libgwenview_export.h" + +class QImage; +class QString; +class QFile; + +namespace ImageUtils { + + +class LIBGWENVIEW_EXPORT JPEGContent { +public: + JPEGContent(); + ~JPEGContent(); + + Orientation orientation() const; + void resetOrientation(); + + int dotsPerMeterX() const; + int dotsPerMeterY() const; + + QSize size() const; + + QString comment() const; + void setComment(const QString&); + + QString aperture() const; + QString exposureTime() const; + QString iso() const; + QString focalLength() const; + + QString getExifInformation(const QString exifkey) const; + + void transform(Orientation); + + QImage thumbnail() const; + void setThumbnail(const QImage&); + + bool load(const QString& file); + bool loadFromData(const QByteArray& rawData); + bool save(const QString& file); + bool save(QFile*); + +private: + struct Private; + Private *d; + + JPEGContent(const JPEGContent&); + void operator=(const JPEGContent&); + void applyPendingTransformation(); + int dotsPerMeter(const QString& keyName) const; +}; + + +} // namespace + + +#endif /* JPEGCONTENT_H */ diff --git a/src/imageutils/jpegerrormanager.h b/src/imageutils/jpegerrormanager.h new file mode 100644 index 0000000..e4f82bb --- /dev/null +++ b/src/imageutils/jpegerrormanager.h @@ -0,0 +1,61 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef JPEGERRORMANAGER_H +#define JPEGERRORMANAGER_H + +#include + +extern "C" { +#define XMD_H +#include +#undef const +} + +namespace ImageUtils { + +/** + * A simple error manager which overrides jpeg_error_mgr.error_exit to avoid + * calls to exit(). It uses setjmp, which I don't like, but I don't fill like + * introducing exceptions to the code base for now. + * + * In order to use it, give an instance of it to jpeg_decompress_struct.err, + * then call setjmp(errorManager.jmp_buffer) + */ +struct JPEGErrorManager : public jpeg_error_mgr { + JPEGErrorManager() : jpeg_error_mgr() { + jpeg_std_error(this); + error_exit=errorExitCallBack; + } + + jmp_buf jmp_buffer; + + static void errorExitCallBack (j_common_ptr cinfo) { + JPEGErrorManager* myerr = static_cast(cinfo->err); + char buffer[JMSG_LENGTH_MAX]; + (*cinfo->err->format_message)(cinfo, buffer); + kdWarning() << k_funcinfo << buffer << endl; + longjmp(myerr->jmp_buffer, 1); + } +}; + +} // namespace + +#endif /* JPEGERRORMANAGER_H */ diff --git a/src/imageutils/jpegint.h b/src/imageutils/jpegint.h new file mode 100644 index 0000000..95b00d4 --- /dev/null +++ b/src/imageutils/jpegint.h @@ -0,0 +1,392 @@ +/* + * jpegint.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides common declarations for the various JPEG modules. + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + + +/* Declarations for both compression & decompression */ + +typedef enum { /* Operating modes for buffer controllers */ + JBUF_PASS_THRU, /* Plain stripwise operation */ + /* Remaining modes require a full-image buffer to have been created */ + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ +} J_BUF_MODE; + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ +#define CSTATE_START 100 /* after create_compress */ +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ +#define DSTATE_START 200 /* after create_decompress */ +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + +/* Declarations for compression modules */ + +/* Master control module */ +struct jpeg_comp_master { + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean call_pass_startup; /* True if pass_startup must be called */ + boolean is_last_pass; /* True during last pass */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_c_main_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail)); +}; + +/* Compression preprocessing (downsampling input buffer control) */ +struct jpeg_c_prep_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, + JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_c_coef_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf)); +}; + +/* Colorspace conversion */ +struct jpeg_color_converter { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +}; + +/* Downsampling */ +struct jpeg_downsampler { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, downsample, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, + JDIMENSION out_row_group_index)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Forward DCT (also controls coefficient quantization) */ +struct jpeg_forward_dct { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + /* perhaps this should be an array??? */ + JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, + jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks)); +}; + +/* Entropy encoding */ +struct jpeg_entropy_encoder { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); + JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); +}; + +/* Marker writing */ +struct jpeg_marker_writer { + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + /* These routines are exported to allow insertion of extra markers */ + /* Probably only COM and APPn markers should be written this way */ + JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, + unsigned int datalen)); + JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); +}; + + +/* Declarations for decompression modules */ + +/* Master control module */ +struct jpeg_decomp_master { + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ +}; + +/* Input control module */ +struct jpeg_input_controller { + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean has_multiple_scans; /* True if file has multiple scans */ + boolean eoi_reached; /* True when EOI has been consumed */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_d_main_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_d_coef_controller { + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + JSAMPIMAGE output_buf)); + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + jvirt_barray_ptr *coef_arrays; +}; + +/* Decompression postprocessing (color quantization buffer control) */ +struct jpeg_d_post_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Marker reading & parsing */ +struct jpeg_marker_reader { + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + /* Read markers until SOS or EOI. + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + /* Read a restart marker --- exported for use by entropy decoder only */ + jpeg_marker_parser_method read_restart_marker; + + /* State of marker reader --- nominally internal, but applications + * supplying COM or APPn handlers might like to know the state. + */ + boolean saw_SOI; /* found SOI? */ + boolean saw_SOF; /* found SOF? */ + int next_restart_num; /* next restart number expected (0-7) */ + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ +}; + +/* Entropy decoding */ +struct jpeg_entropy_decoder { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + /* This is here to share code between baseline and progressive decoders; */ + /* other modules probably should not use it */ + boolean insufficient_data; /* set TRUE after emitting warning */ +}; + +/* Inverse DCT (also performs dequantization) */ +typedef JMETHOD(void, inverse_DCT_method_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col)); + +struct jpeg_inverse_dct { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + /* It is useful to allow each component to have a separate IDCT method. */ + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; +}; + +/* Upsampling (note that upsampler must also call color converter) */ +struct jpeg_upsampler { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Colorspace conversion */ +struct jpeg_color_deconverter { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +}; + +/* Color quantization or color precision reduction */ +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + +/* Miscellaneous useful macros */ + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_compress_master jICompress +#define jinit_c_master_control jICMaster +#define jinit_c_main_controller jICMainC +#define jinit_c_prep_controller jICPrepC +#define jinit_c_coef_controller jICCoefC +#define jinit_color_converter jICColor +#define jinit_downsampler jIDownsampler +#define jinit_forward_dct jIFDCT +#define jinit_huff_encoder jIHEncoder +#define jinit_phuff_encoder jIPHEncoder +#define jinit_marker_writer jIMWriter +#define jinit_master_decompress jIDMaster +#define jinit_d_main_controller jIDMainC +#define jinit_d_coef_controller jIDCoefC +#define jinit_d_post_controller jIDPostC +#define jinit_input_controller jIInCtlr +#define jinit_marker_reader jIMReader +#define jinit_huff_decoder jIHDecoder +#define jinit_phuff_decoder jIPHDecoder +#define jinit_inverse_dct jIIDCT +#define jinit_upsampler jIUpsampler +#define jinit_color_deconverter jIDColor +#define jinit_1pass_quantizer jI1Quant +#define jinit_2pass_quantizer jI2Quant +#define jinit_merged_upsampler jIMUpsampler +#define jinit_memory_mgr jIMemMgr +#define jdiv_round_up jDivRound +#define jround_up jRound +#define jcopy_sample_rows jCopySamples +#define jcopy_block_row jCopyBlocks +#define jzero_far jZeroFar +#define jpeg_zigzag_order jZIGTable +#define jpeg_natural_order jZAGTable +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Compression module initialization routines */ +EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, + boolean transcode_only)); +EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +/* Memory manager initialization */ +EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); + +/* Utility routines in jutils.c */ +EXTERN(long) jdiv_round_up JPP((long a, long b)); +EXTERN(long) jround_up JPP((long a, long b)); +EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols)); +EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks)); +EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); +/* Constant tables in jutils.c */ +#if 0 /* This table is not actually needed in v6a */ +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ +#endif +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ + +/* Suppress undefined-structure complaints if necessary. */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +#endif +#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/src/imageutils/orient6.jpg b/src/imageutils/orient6.jpg new file mode 100644 index 0000000..db1002b Binary files /dev/null and b/src/imageutils/orient6.jpg differ diff --git a/src/imageutils/orientation.h b/src/imageutils/orientation.h new file mode 100644 index 0000000..64f0ad8 --- /dev/null +++ b/src/imageutils/orientation.h @@ -0,0 +1,58 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef ORIENTATION_H +#define ORIENTATION_H + + +namespace ImageUtils { + +/* Explanation extracted from http://sylvana.net/jpegcrop/exif_orientation.html + + For convenience, here is what the letter F would look like if it were tagged +correctly and displayed by a program that ignores the orientation tag (thus +showing the stored image): + + 1 2 3 4 5 6 7 8 + +888888 888888 88 88 8888888888 88 88 8888888888 +88 88 88 88 88 88 88 88 88 88 88 88 +8888 8888 8888 8888 88 8888888888 8888888888 88 +88 88 88 88 +88 88 888888 888888 + +*/ + +enum Orientation { + NOT_AVAILABLE=0, + NORMAL=1, + HFLIP=2, + ROT_180=3, + VFLIP=4, + TRANSPOSE=5, + ROT_90=6, + TRANSVERSE=7, + ROT_270=8 +}; + +} + + +#endif diff --git a/src/imageutils/scale.cpp b/src/imageutils/scale.cpp new file mode 100644 index 0000000..99ed186 --- /dev/null +++ b/src/imageutils/scale.cpp @@ -0,0 +1,1979 @@ +// This file includes code for scaling images, in two versions. +// One ported from ImageMagick (slower, but can achieve better quality), +// and from Imlib2 ported by Mosfet (very fast). + + +// ImageMagick code begin +// ---------------------- + +// This code is ImageMagick's resize code, adapted for QImage, with +// fastfloat class added as an optimization. +// The original license text follows. + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% RRRR EEEEE SSSSS IIIII ZZZZZ EEEEE % +% R R E SS I ZZ E % +% RRRR EEE SSS I ZZZ EEE % +% R R E SS I ZZ E % +% R R EEEEE SSSSS IIIII ZZZZZ EEEEE % +% % +% ImageMagick Image Resize Methods % +% % +% % +% Software Design % +% John Cristy % +% July 1992 % +% % +% % +% Copyright (C) 2003 ImageMagick Studio, a non-profit organization dedicated % +% to making software imaging solutions freely available. % +% % +% Permission is hereby granted, free of charge, to any person obtaining a % +% copy of this software and associated documentation files ("ImageMagick"), % +% to deal in ImageMagick without restriction, including without limitation % +% the rights to use, copy, modify, merge, publish, distribute, sublicense, % +% and/or sell copies of ImageMagick, and to permit persons to whom the % +% ImageMagick 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 ImageMagick. % +% % +% 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 % +% ImageMagick Studio 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 ImageMagick or the use or other dealings in % +% ImageMagick. % +% % +% Except as contained in this notice, the name of the ImageMagick Studio % +% shall not be used in advertising or otherwise to promote the sale, use or % +% other dealings in ImageMagick without prior written authorization from the % +% ImageMagick Studio. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% +*/ +#include "config.h" + +// System +#ifdef HAVE_ENDIAN_H +#include +#else +#ifdef HAVE_SYS_ENDIAN_H +#include +#endif +#endif + +// Qt +#include +#include + +#include +#include + +#include +#include + +// Local +#include "imageutils.h" + +// everything in namespace +namespace ImageUtils { + + +#define Max QMAX +#define Min QMIN + +// mustn't be less than used precision (i.e. 1/fastfloat::RATIO) +#define MagickEpsilon 0.0002 + +// fastfloat begin +// this class stores floating point numbers as integers, with BITS shift, +// i.e. value XYZ is stored as XYZ * RATIO +struct fastfloat + { + private: + enum { BITS = 12, RATIO = 4096 }; + public: + fastfloat() {} + fastfloat( long v ) : value( v << BITS ) {} + fastfloat( int v ) : value( v << BITS ) {} + fastfloat( double v ) : value( static_cast< long >( v * RATIO + 0.5 )) {} + double toDouble() const { return static_cast< double >( value ) / RATIO; } + long toLong() const { return value >> BITS; } + fastfloat& operator += ( fastfloat r ) { value += r.value; return *this; } + fastfloat& operator -= ( fastfloat r ) { value -= r.value; return *this; } + fastfloat& operator *= ( fastfloat r ) { value = static_cast< long long >( value ) * r.value >> BITS; return *this; } + fastfloat& operator /= ( fastfloat r ) { value = ( static_cast< long long >( value ) << BITS ) / r.value; return *this; } + bool operator< ( fastfloat r ) const { return value < r.value; } + bool operator<= ( fastfloat r ) const { return value <= r.value; } + bool operator> ( fastfloat r ) const { return value > r.value; } + bool operator>= ( fastfloat r ) const { return value >= r.value; } + bool operator== ( fastfloat r ) const { return value == r.value; } + bool operator!= ( fastfloat r ) const { return value != r.value; } + fastfloat operator-() const { return fastfloat( -value, false ); } + private: + fastfloat( long v, bool ) : value( v ) {} // for operator-() + long value; + }; + +inline fastfloat operator+ ( fastfloat l, fastfloat r ) { return fastfloat( l ) += r; } +inline fastfloat operator- ( fastfloat l, fastfloat r ) { return fastfloat( l ) -= r; } +inline fastfloat operator* ( fastfloat l, fastfloat r ) { return fastfloat( l ) *= r; } +inline fastfloat operator/ ( fastfloat l, fastfloat r ) { return fastfloat( l ) /= r; } + +inline bool operator< ( fastfloat l, double r ) { return l < fastfloat( r ); } +inline bool operator<= ( fastfloat l, double r ) { return l <= fastfloat( r ); } +inline bool operator> ( fastfloat l, double r ) { return l > fastfloat( r ); } +inline bool operator>= ( fastfloat l, double r ) { return l >= fastfloat( r ); } +inline bool operator== ( fastfloat l, double r ) { return l == fastfloat( r ); } +inline bool operator!= ( fastfloat l, double r ) { return l != fastfloat( r ); } + +inline bool operator< ( double l, fastfloat r ) { return fastfloat( l ) < r ; } +inline bool operator<= ( double l, fastfloat r ) { return fastfloat( l ) <= r ; } +inline bool operator> ( double l, fastfloat r ) { return fastfloat( l ) > r ; } +inline bool operator>= ( double l, fastfloat r ) { return fastfloat( l ) >= r ; } +inline bool operator== ( double l, fastfloat r ) { return fastfloat( l ) == r ; } +inline bool operator!= ( double l, fastfloat r ) { return fastfloat( l ) != r ; } + +inline double fasttodouble( fastfloat v ) { return v.toDouble(); } +inline long fasttolong( fastfloat v ) { return v.toLong(); } + +#if 1 // change to 0 to turn fastfloat usage off +#else +#define fastfloat double +#define fasttodouble( v ) double( v ) +#define fasttolong( v ) long( v ) +#endif + +//fastfloat end + + +typedef fastfloat (*Filter)(const fastfloat, const fastfloat); + +typedef struct _ContributionInfo +{ + fastfloat + weight; + + long + pixel; +} ContributionInfo; + + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% R e s i z e I m a g e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% ResizeImage() scales an image to the desired dimensions with one of these +% filters: +% +% Bessel Blackman Box +% Catrom Cubic Gaussian +% Hanning Hermite Lanczos +% Mitchell Point Quandratic +% Sinc Triangle +% +% Most of the filters are FIR (finite impulse response), however, Bessel, +% Gaussian, and Sinc are IIR (infinite impulse response). Bessel and Sinc +% are windowed (brought down to zero) with the Blackman filter. +% +% ResizeImage() was inspired by Paul Heckbert's zoom program. +% +% The format of the ResizeImage method is: +% +% Image *ResizeImage(Image *image,const unsigned long columns, +% const unsigned long rows,const FilterTypes filter,const double blur, +% ExceptionInfo *exception) +% +% A description of each parameter follows: +% +% o image: The image. +% +% o columns: The number of columns in the scaled image. +% +% o rows: The number of rows in the scaled image. +% +% o filter: Image filter to use. +% +% o blur: The blur factor where > 1 is blurry, < 1 is sharp. +% +% o exception: Return any errors or warnings in this structure. +% +% +*/ + +#if 0 +static fastfloat Bessel(const fastfloat x,const fastfloat) +{ + if (x == 0.0) + return(MagickPI/4.0); + return(BesselOrderOne(MagickPI*x)/(2.0*x)); +} + +static fastfloat Sinc(const fastfloat x,const fastfloat) +{ + if (x == 0.0) + return(1.0); + return(sin(MagickPI*x)/(MagickPI*x)); +} + +static fastfloat Blackman(const fastfloat x,const fastfloat) +{ + return(0.42+0.5*cos(MagickPI*x)+0.08*cos(2*MagickPI*x)); +} + +static fastfloat BlackmanBessel(const fastfloat x,const fastfloat) +{ + return(Blackman(x/support,support)*Bessel(x,support)); +} + +static fastfloat BlackmanSinc(const fastfloat x,const fastfloat) +{ + return(Blackman(x/support,support)*Sinc(x,support)); +} +#endif + +static fastfloat Box(const fastfloat x,const fastfloat) +{ + if (x < -0.5) + return(0.0); + if (x < 0.5) + return(1.0); + return(0.0); +} + +#if 0 +static fastfloat Catrom(const fastfloat x,const fastfloat) +{ + if (x < -2.0) + return(0.0); + if (x < -1.0) + return(0.5*(4.0+x*(8.0+x*(5.0+x)))); + if (x < 0.0) + return(0.5*(2.0+x*x*(-5.0-3.0*x))); + if (x < 1.0) + return(0.5*(2.0+x*x*(-5.0+3.0*x))); + if (x < 2.0) + return(0.5*(4.0+x*(-8.0+x*(5.0-x)))); + return(0.0); +} + +static fastfloat Cubic(const fastfloat x,const fastfloat) +{ + if (x < -2.0) + return(0.0); + if (x < -1.0) + return((2.0+x)*(2.0+x)*(2.0+x)/6.0); + if (x < 0.0) + return((4.0+x*x*(-6.0-3.0*x))/6.0); + if (x < 1.0) + return((4.0+x*x*(-6.0+3.0*x))/6.0); + if (x < 2.0) + return((2.0-x)*(2.0-x)*(2.0-x)/6.0); + return(0.0); +} + +static fastfloat Gaussian(const fastfloat x,const fastfloat) +{ + return(exp(-2.0*x*x)*sqrt(2.0/MagickPI)); +} + +static fastfloat Hanning(const fastfloat x,const fastfloat) +{ + return(0.5+0.5*cos(MagickPI*x)); +} + +static fastfloat Hamming(const fastfloat x,const fastfloat) +{ + return(0.54+0.46*cos(MagickPI*x)); +} + +static fastfloat Hermite(const fastfloat x,const fastfloat) +{ + if (x < -1.0) + return(0.0); + if (x < 0.0) + return((2.0*(-x)-3.0)*(-x)*(-x)+1.0); + if (x < 1.0) + return((2.0*x-3.0)*x*x+1.0); + return(0.0); +} + +static fastfloat Lanczos(const fastfloat x,const fastfloat support) +{ + if (x < -3.0) + return(0.0); + if (x < 0.0) + return(Sinc(-x,support)*Sinc(-x/3.0,support)); + if (x < 3.0) + return(Sinc(x,support)*Sinc(x/3.0,support)); + return(0.0); +} + +static fastfloat Mitchell(const fastfloat x,const fastfloat) +{ +#define B (1.0/3.0) +#define C (1.0/3.0) +#define P0 (( 6.0- 2.0*B )/6.0) +#define P2 ((-18.0+12.0*B+ 6.0*C)/6.0) +#define P3 (( 12.0- 9.0*B- 6.0*C)/6.0) +#define Q0 (( 8.0*B+24.0*C)/6.0) +#define Q1 (( -12.0*B-48.0*C)/6.0) +#define Q2 (( 6.0*B+30.0*C)/6.0) +#define Q3 (( - 1.0*B- 6.0*C)/6.0) + + if (x < -2.0) + return(0.0); + if (x < -1.0) + return(Q0-x*(Q1-x*(Q2-x*Q3))); + if (x < 0.0) + return(P0+x*x*(P2-x*P3)); + if (x < 1.0) + return(P0+x*x*(P2+x*P3)); + if (x < 2.0) + return(Q0+x*(Q1+x*(Q2+x*Q3))); + return(0.0); + +#undef B +#undef C +#undef P0 +#undef P2 +#undef P3 +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 +} +#endif + +// this is the same like Mitchell, but it has different values +// for B and C, resulting in sharper images +// http://sourceforge.net/mailarchive/forum.php?thread_id=7445822&forum_id=1210 +static fastfloat Bicubic(const fastfloat x,const fastfloat) +{ +#define B (0.0/3.0) +#define C (2.0/3.0) +#define P0 (( 6.0- 2.0*B )/6.0) +#define P2 ((-18.0+12.0*B+ 6.0*C)/6.0) +#define P3 (( 12.0- 9.0*B- 6.0*C)/6.0) +#define Q0 (( 8.0*B+24.0*C)/6.0) +#define Q1 (( -12.0*B-48.0*C)/6.0) +#define Q2 (( 6.0*B+30.0*C)/6.0) +#define Q3 (( - 1.0*B- 6.0*C)/6.0) + + if (x < -2.0) + return(0.0); + if (x < -1.0) + return(Q0-x*(Q1-x*(Q2-x*Q3))); + if (x < 0.0) + return(P0+x*x*(P2-x*P3)); + if (x < 1.0) + return(P0+x*x*(P2+x*P3)); + if (x < 2.0) + return(Q0+x*(Q1+x*(Q2+x*Q3))); + return(0.0); + +#undef B +#undef C +#undef P0 +#undef P2 +#undef P3 +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 +} + +#if 0 +static fastfloat Quadratic(const fastfloat x,const fastfloat) +{ + if (x < -1.5) + return(0.0); + if (x < -0.5) + return(0.5*(x+1.5)*(x+1.5)); + if (x < 0.5) + return(0.75-x*x); + if (x < 1.5) + return(0.5*(x-1.5)*(x-1.5)); + return(0.0); +} +#endif + +static fastfloat Triangle(const fastfloat x,const fastfloat) +{ + if (x < -1.0) + return(0.0); + if (x < 0.0) + return(1.0+x); + if (x < 1.0) + return(1.0-x); + return(0.0); +} + +static void HorizontalFilter(const QImage& source,QImage& destination, + const fastfloat x_factor,const fastfloat blur, + ContributionInfo *contribution, Filter filter, fastfloat filtersupport) +{ + fastfloat + center, + density, + scale, + support; + + long + n, + start, + stop, + y; + + register long + i, + x; + + /* + Apply filter to resize horizontally from source to destination. + */ + scale=blur*Max(1.0/x_factor,1.0); + support=scale* filtersupport; + if (support <= 0.5) + { + /* + Reduce to point sampling. + */ + support=0.5+MagickEpsilon; + scale=1.0; + } + scale=1.0/scale; + for (x=0; x < (long) destination.width(); x++) + { + center=(fastfloat) (x+0.5)/x_factor; + start= fasttolong(Max(center-support+0.5,0)); + stop= fasttolong(Min(center+support+0.5,source.width())); + density=0.0; + for (n=0; n < (stop-start); n++) + { + contribution[n].pixel=start+n; + contribution[n].weight= + filter (scale*(start+n-center+0.5), filtersupport ); + density+=contribution[n].weight; + } + if ((density != 0.0) && (density != 1.0)) + { + /* + Normalize. + */ + density=1.0/density; + for (i=0; i < n; i++) + contribution[i].weight*=density; + } +// p=AcquireImagePixels(source,contribution[0].pixel,0,contribution[n-1].pixel- +// contribution[0].pixel+1,source->rows,exception); +// q=SetImagePixels(destination,x,0,1,destination->rows); + for (y=0; y < (long) destination.height(); y++) + { + fastfloat red = 0; + fastfloat green = 0; + fastfloat blue = 0; + fastfloat alpha = 0; + for (i=0; i < n; i++) + { + int px = contribution[i].pixel; + int py = y; + QRgb p = reinterpret_cast< QRgb* >( source.jumpTable()[ py ])[ px ]; + red+=contribution[i].weight*qRed(p); + green+=contribution[i].weight*qGreen(p); + blue+=contribution[i].weight*qBlue(p); + alpha+=contribution[i].weight*qAlpha(p); + } + QRgb pix = qRgba( + fasttolong( red < 0 ? 0 : red > 255 ? 255 : red + 0.5 ), + fasttolong( green < 0 ? 0 : green > 255 ? 255 : green + 0.5 ), + fasttolong( blue < 0 ? 0 : blue > 255 ? 255 : blue + 0.5 ), + fasttolong( alpha < 0 ? 0 : alpha > 255 ? 255 : alpha + 0.5 )); + reinterpret_cast< QRgb* >( destination.jumpTable()[ y ])[ x ] = pix; + } + } +} + +static void VerticalFilter(const QImage& source,QImage& destination, + const fastfloat y_factor,const fastfloat blur, + ContributionInfo *contribution, Filter filter, fastfloat filtersupport ) +{ + fastfloat + center, + density, + scale, + support; + + long + n, + start, + stop, + x; + + register long + i, + y; + + /* + Apply filter to resize vertically from source to destination. + */ + scale=blur*Max(1.0/y_factor,1.0); + support=scale* filtersupport; + if (support <= 0.5) + { + /* + Reduce to point sampling. + */ + support=0.5+MagickEpsilon; + scale=1.0; + } + scale=1.0/scale; + for (y=0; y < (long) destination.height(); y++) + { + center=(fastfloat) (y+0.5)/y_factor; + start= fasttolong(Max(center-support+0.5,0)); + stop= fasttolong(Min(center+support+0.5,source.height())); + density=0.0; + for (n=0; n < (stop-start); n++) + { + contribution[n].pixel=start+n; + contribution[n].weight= + filter (scale*(start+n-center+0.5), filtersupport); + density+=contribution[n].weight; + } + if ((density != 0.0) && (density != 1.0)) + { + /* + Normalize. + */ + density=1.0/density; + for (i=0; i < n; i++) + contribution[i].weight*=density; + } +// p=AcquireImagePixels(source,0,contribution[0].pixel,source->columns, +// contribution[n-1].pixel-contribution[0].pixel+1,exception); +// q=SetImagePixels(destination,0,y,destination->columns,1); + for (x=0; x < (long) destination.width(); x++) + { + fastfloat red = 0; + fastfloat green = 0; + fastfloat blue = 0; + fastfloat alpha = 0; + for (i=0; i < n; i++) + { + int px = x; + int py = contribution[i].pixel; + QRgb p = reinterpret_cast< QRgb* >( source.jumpTable()[ py ])[ px ]; + red+=contribution[i].weight*qRed(p); + green+=contribution[i].weight*qGreen(p); + blue+=contribution[i].weight*qBlue(p); + alpha+=contribution[i].weight*qAlpha(p); + } + QRgb pix = qRgba( + fasttolong( red < 0 ? 0 : red > 255 ? 255 : red + 0.5 ), + fasttolong( green < 0 ? 0 : green > 255 ? 255 : green + 0.5 ), + fasttolong( blue < 0 ? 0 : blue > 255 ? 255 : blue + 0.5 ), + fasttolong( alpha < 0 ? 0 : alpha > 255 ? 255 : alpha + 0.5 )); + reinterpret_cast< QRgb* >( destination.jumpTable()[ y ])[ x ] = pix; + } + } +} + +static QImage ResizeImage(const QImage& image,const int columns, + const int rows, Filter filter, fastfloat filtersupport, double blur) +{ + ContributionInfo + *contribution; + + fastfloat + support, + x_factor, + x_support, + y_factor, + y_support; + + /* + Initialize resize image attributes. + */ + if ((columns == image.width()) && (rows == image.height()) && (blur == 1.0)) + return image.copy(); + QImage resize_image( columns, rows, 32 ); + resize_image.setAlphaBuffer( image.hasAlphaBuffer()); + /* + Allocate filter contribution info. + */ + x_factor=(fastfloat) resize_image.width()/image.width(); + y_factor=(fastfloat) resize_image.height()/image.height(); +// i=(long) LanczosFilter; +// if (image->filter != UndefinedFilter) +// i=(long) image->filter; +// else +// if ((image->storage_class == PseudoClass) || image->matte || +// ((x_factor*y_factor) > 1.0)) +// i=(long) MitchellFilter; + x_support=blur*Max(1.0/x_factor,1.0)*filtersupport; + y_support=blur*Max(1.0/y_factor,1.0)*filtersupport; + support=Max(x_support,y_support); + if (support < filtersupport) + support=filtersupport; + contribution=new ContributionInfo[ fasttolong( 2.0*Max(support,0.5)+3 ) ]; + Q_CHECK_PTR( contribution ); + /* + Resize image. + */ + if (((fastfloat) columns*(image.height()+rows)) > + ((fastfloat) rows*(image.width()+columns))) + { + QImage source_image( columns, image.height(), 32 ); + source_image.setAlphaBuffer( image.hasAlphaBuffer()); + HorizontalFilter(image,source_image,x_factor,blur, + contribution,filter,filtersupport); + VerticalFilter(source_image,resize_image,y_factor, + blur,contribution,filter,filtersupport); + } + else + { + QImage source_image( image.width(), rows, 32 ); + source_image.setAlphaBuffer( image.hasAlphaBuffer()); + VerticalFilter(image,source_image,y_factor,blur, + contribution,filter,filtersupport); + HorizontalFilter(source_image,resize_image,x_factor, + blur,contribution,filter,filtersupport); + } + /* + Free allocated memory. + */ + delete[] contribution; + return(resize_image); +} + + +#undef Max +#undef Min +#undef MagickEpsilon + + +// filters and their matching support values +#if 0 + static const FilterInfo + filters[SincFilter+1] = + { + { Box, 0.0 }, + { Box, 0.0 }, + { Box, 0.5 }, + { Triangle, 1.0 }, + { Hermite, 1.0 }, + { Hanning, 1.0 }, + { Hamming, 1.0 }, + { Blackman, 1.0 }, + { Gaussian, 1.25 }, + { Quadratic, 1.5 }, + { Cubic, 2.0 }, + { Catrom, 2.0 }, + { Mitchell, 2.0 }, + { Lanczos, 3.0 }, + { BlackmanBessel, 3.2383 }, + { BlackmanSinc, 4.0 } + }; +#endif + + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% S a m p l e I m a g e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% SampleImage() scales an image to the desired dimensions with pixel +% sampling. Unlike other scaling methods, this method does not introduce +% any additional color into the scaled image. +% +% The format of the SampleImage method is: +% +% Image *SampleImage(const Image *image,const unsigned long columns, +% const unsigned long rows,ExceptionInfo *exception) +% +% A description of each parameter follows: +% +% o image: The image. +% +% o columns: The number of columns in the sampled image. +% +% o rows: The number of rows in the sampled image. +% +% o exception: Return any errors or warnings in this structure. +% +% +*/ +QImage SampleImage(const QImage& image,const int columns, + const int rows) +{ + int + *x_offset, + *y_offset; + + long + j, + y; + + uchar + *pixels; + + register const uchar + *p; + + register long + x; + + register uchar + *q; + + /* + Initialize sampled image attributes. + */ + if ((columns == image.width()) && (rows == image.height())) + return image; + // This function is modified to handle any image depth, not only + // 32bit like the ImageMagick original. This avoids the relatively + // expensive conversion. + const int d = image.depth() / 8; + QImage sample_image( columns, rows, image.depth()); + sample_image.setAlphaBuffer( image.hasAlphaBuffer()); + /* + Allocate scan line buffer and column offset buffers. + */ + pixels= new uchar[ image.width() * d ]; + x_offset= new int[ sample_image.width() ]; + y_offset= new int[ sample_image.height() ]; + /* + Initialize pixel offsets. + */ +// In the following several code 0.5 needs to be added, otherwise the image +// would be moved by half a pixel to bottom-right, just like +// with Qt's QImage::scale() + for (x=0; x < (long) sample_image.width(); x++) + { + x_offset[x]=int((x+0.5)*image.width()/sample_image.width()); + } + for (y=0; y < (long) sample_image.height(); y++) + { + y_offset[y]=int((y+0.5)*image.height()/sample_image.height()); + } + /* + Sample each row. + */ + j=(-1); + for (y=0; y < (long) sample_image.height(); y++) + { + q= sample_image.scanLine( y ); + if (j != y_offset[y] ) + { + /* + Read a scan line. + */ + j= y_offset[y]; + p= image.scanLine( j ); + (void) memcpy(pixels,p,image.width()*d); + } + /* + Sample each column. + */ + switch( d ) + { + case 1: // 8bit + for (x=0; x < (long) sample_image.width(); x++) + { + *q++=pixels[ x_offset[x] ]; + } + break; + case 4: // 32bit + for (x=0; x < (long) sample_image.width(); x++) + { + *(QRgb*)q=((QRgb*)pixels)[ x_offset[x] ]; + q += d; + } + break; + default: + for (x=0; x < (long) sample_image.width(); x++) + { + memcpy( q, pixels + x_offset[x] * d, d ); + q += d; + } + break; + } + } + if( d != 4 ) // != 32bit + { + sample_image.setNumColors( image.numColors()); + for( int i = 0; i < image.numColors(); ++i ) + sample_image.setColor( i, image.color( i )); + } + delete[] y_offset; + delete[] x_offset; + delete[] pixels; + return sample_image; +} + + +// ImageMagick code end + + +// Imlib2/Mosfet code begin +// ------------------------ + +// This code is Imlib2 code, additionally modified by Mosfet, and with few small +// modifications for Gwenview. The MMX scaling code also belongs to it. + +// The original license texts follow. + +/** + * This is the normal smoothscale method, based on Imlib2's smoothscale. + * + * Originally I took the algorithm used in NetPBM and Qt and added MMX/3dnow + * optimizations. It ran in about 1/2 the time as Qt. Then I ported Imlib's + * C algorithm and it ran at about the same speed as my MMX optimized one... + * Finally I ported Imlib's MMX version and it ran in less than half the + * time as my MMX algorithm, (taking only a quarter of the time Qt does). + * + * Changes include formatting, namespaces and other C++'ings, removal of old + * #ifdef'ed code, and removal of unneeded border calculation code. + * + * Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code + * is by Willem Monsuwe . All other modifications are + * (C) Daniel M. Duley. + */ + +/* + Copyright (C) 2004 Daniel M. Duley + +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. + +*/ + +/* +Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) + +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, sublicense, 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 of the Software and its Copyright notices. In addition publicly +documented acknowledgment must be given that this software has been used if no +source code of this software is made available publicly. This includes +acknowledgments in either Copyright notices, Manuals, Publicity and Marketing +documents or any documentation provided with any product containing this +software. This License does not apply to any software that links to the +libraries provided by this software (statically or dynamically), but only to +the software provided. + +Please see the COPYING.PLAIN for a plain-english explanation of this notice +and it's intent. + +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. +*/ + +namespace MImageScale{ + typedef struct __mimage_scale_info + { + int *xpoints; + unsigned int **ypoints; + int *xapoints, *yapoints; + int xup_yup; + } MImageScaleInfo; + + unsigned int** mimageCalcYPoints(unsigned int *src, int sow, int sh, + int dh); + int* mimageCalcXPoints(int sw, int dw); + int* mimageCalcApoints(int s, int d, int up); + MImageScaleInfo* mimageFreeScaleInfo(MImageScaleInfo *isi); + MImageScaleInfo *mimageCalcScaleInfo(QImage &img, int sw, int sh, + int dw, int dh, char aa, int sow); + void mimageSampleRGBA(MImageScaleInfo *isi, unsigned int *dest, int dxx, + int dyy, int dx, int dy, int dw, int dh, int dow); + void mimageScaleAARGBA(MImageScaleInfo *isi, unsigned int *dest, int dxx, + int dyy, int dx, int dy, int dw, int dh, int dow, + int sow); + void mimageScaleAARGB(MImageScaleInfo *isi, unsigned int *dest, int dxx, + int dyy, int dx, int dy, int dw, int dh, int dow, int + sow); + QImage smoothScale(const QImage& img, int dw, int dh); + typedef long long llong; +} + +#ifdef HAVE_X86_MMX +extern "C" { + void __mimageScale_mmx_AARGBA(MImageScale::MImageScaleInfo *isi, + unsigned int *dest, int dxx, int dyy, + int dx, int dy, int dw, int dh, + int dow, int sow); +} +#endif + +using namespace MImageScale; + +QImage MImageScale::smoothScale(const QImage& image, int dw, int dh) +{ + QImage img = image.depth() < 32 ? image.convertDepth( 32 ) : image; + int w = img.width(); + int h = img.height(); + + int sow = img.bytesPerLine(); + // handle CroppedQImage + if( img.height() > 1 && sow != img.scanLine( 1 ) - img.scanLine( 0 )) + sow = img.scanLine( 1 ) - img.scanLine( 0 ); + sow = sow / ( img.depth() / 8 ); + + MImageScaleInfo *scaleinfo = + mimageCalcScaleInfo(img, w, h, dw, dh, true, sow); + if(!scaleinfo) + return QImage(); + + QImage buffer(dw, dh, 32); + buffer.setAlphaBuffer(img.hasAlphaBuffer()); + +#ifdef HAVE_X86_MMX +//#warning Using MMX Smoothscale + bool haveMMX = KCPUInfo::haveExtension( KCPUInfo::IntelMMX ); + if(haveMMX){ + __mimageScale_mmx_AARGBA(scaleinfo, (unsigned int *)buffer.scanLine(0), + 0, 0, 0, 0, dw, dh, dw, sow); + } + else +#endif + { + if(img.hasAlphaBuffer()) + mimageScaleAARGBA(scaleinfo, (unsigned int *)buffer.scanLine(0), 0, 0, + 0, 0, dw, dh, dw, sow); + else + mimageScaleAARGB(scaleinfo, (unsigned int *)buffer.scanLine(0), 0, 0, + 0, 0, dw, dh, dw, sow); + } + mimageFreeScaleInfo(scaleinfo); + return(buffer); +} + +// +// Code ported from Imlib... +// + +// FIXME: replace with mRed, etc... These work on pointers to pixels, not +// pixel values +#if BYTE_ORDER == BIG_ENDIAN +#define A_VAL(p) ((unsigned char *)(p))[0] +#define R_VAL(p) ((unsigned char *)(p))[1] +#define G_VAL(p) ((unsigned char *)(p))[2] +#define B_VAL(p) ((unsigned char *)(p))[3] +#elif BYTE_ORDER == LITTLE_ENDIAN +#define A_VAL(p) ((unsigned char *)(p))[3] +#define R_VAL(p) ((unsigned char *)(p))[2] +#define G_VAL(p) ((unsigned char *)(p))[1] +#define B_VAL(p) ((unsigned char *)(p))[0] +#else +#error "BYTE_ORDER is not defined" +#endif + +#define INV_XAP (256 - xapoints[x]) +#define XAP (xapoints[x]) +#define INV_YAP (256 - yapoints[dyy + y]) +#define YAP (yapoints[dyy + y]) + +unsigned int** MImageScale::mimageCalcYPoints(unsigned int *src, + int sow, int sh, int dh) +{ + unsigned int **p; + int i, j = 0; + int rv = 0; + llong val, inc; + + if(dh < 0){ + dh = -dh; + rv = 1; + } + p = new unsigned int* [dh+1]; + + val = 0; + inc = (llong(sh) << 16) / dh; + for(i = 0; i < dh; i++){ + p[j++] = src + ((val >> 16) * sow); + val += inc; + } + if(rv){ + for(i = dh / 2; --i >= 0; ){ + unsigned int *tmp = p[i]; + p[i] = p[dh - i - 1]; + p[dh - i - 1] = tmp; + } + } + return(p); +} + +int* MImageScale::mimageCalcXPoints(int sw, int dw) +{ + int *p, i, j = 0; + int rv = 0; + llong val, inc; + + if(dw < 0){ + dw = -dw; + rv = 1; + } + p = new int[dw+1]; + + val = 0; + inc = (llong(sw) << 16) / dw; + for(i = 0; i < dw; i++){ + p[j++] = (val >> 16); + val += inc; + } + + if(rv){ + for(i = dw / 2; --i >= 0; ){ + int tmp = p[i]; + p[i] = p[dw - i - 1]; + p[dw - i - 1] = tmp; + } + } + return(p); +} + +int* MImageScale::mimageCalcApoints(int s, int d, int up) +{ + int *p, i, j = 0, rv = 0; + + if(d < 0){ + rv = 1; + d = -d; + } + p = new int[d]; + + /* scaling up */ + if(up){ + llong val, inc; + + val = 0; + inc = (llong(s) << 16) / d; + for(i = 0; i < d; i++){ + p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00); + if((val >> 16) >= (s - 1)) + p[j - 1] = 0; + val += inc; + } + } + /* scaling down */ + else{ + llong val, inc; + int ap, Cp; + val = 0; + inc = (llong(s) << 16) / d; + Cp = ((llong(d) << 14) / s) + 1; + for(i = 0; i < d; i++){ + ap = ((0x100 - ((val >> 8) & 0xff)) * Cp) >> 8; + p[j] = ap | (Cp << 16); + j++; + val += inc; + } + } + if(rv){ + int tmp; + for(i = d / 2; --i >= 0; ){ + tmp = p[i]; + p[i] = p[d - i - 1]; + p[d - i - 1] = tmp; + } + } + return(p); +} + +MImageScaleInfo* MImageScale::mimageFreeScaleInfo(MImageScaleInfo *isi) +{ + if(isi){ + delete[] isi->xpoints; + delete[] isi->ypoints; + delete[] isi->xapoints; + delete[] isi->yapoints; + delete isi; + } + return(NULL); +} + +MImageScaleInfo* MImageScale::mimageCalcScaleInfo(QImage &img, int sw, int sh, + int dw, int dh, char aa, int sow) +{ + MImageScaleInfo *isi; + int scw, sch; + + scw = dw * img.width() / sw; + sch = dh * img.height() / sh; + + isi = new MImageScaleInfo; + if(!isi) + return(NULL); + memset(isi, 0, sizeof(MImageScaleInfo)); + + isi->xup_yup = (abs(dw) >= sw) + ((abs(dh) >= sh) << 1); + + isi->xpoints = mimageCalcXPoints(img.width(), scw); + if(!isi->xpoints) + return(mimageFreeScaleInfo(isi)); + isi->ypoints = mimageCalcYPoints((unsigned int *)img.scanLine(0), + sow, img.height(), sch ); + if (!isi->ypoints) + return(mimageFreeScaleInfo(isi)); + if(aa){ + isi->xapoints = mimageCalcApoints(img.width(), scw, isi->xup_yup & 1); + if(!isi->xapoints) + return(mimageFreeScaleInfo(isi)); + isi->yapoints = mimageCalcApoints(img.height(), sch, isi->xup_yup & 2); + if(!isi->yapoints) + return(mimageFreeScaleInfo(isi)); + } + return(isi); +} + +/* scale by pixel sampling only */ +void MImageScale::mimageSampleRGBA(MImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow) +{ + unsigned int *sptr, *dptr; + int x, y, end; + unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + + /* whats the last pixel ont he line so we stop there */ + end = dxx + dw; + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + /* get the pointer to the start of the destination scanline */ + dptr = dest + dx + ((y + dy) * dow); + /* calculate the source line we'll scan from */ + sptr = ypoints[dyy + y]; + /* go thru the scanline and copy across */ + for(x = dxx; x < end; x++) + *dptr++ = sptr[xpoints[x]]; + } +} + +/* FIXME: NEED to optimise ScaleAARGBA - currently its "ok" but needs work*/ + +/* scale by area sampling */ +void MImageScale::mimageScaleAARGBA(MImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + unsigned int *sptr, *dptr; + int x, y, end; + unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + end = dxx + dw; + /* scaling up both ways */ + if(isi->xup_yup == 3){ + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + if(YAP > 0){ + for(x = dxx; x < end; x++){ + int r, g, b, a; + int rr, gg, bb, aa; + unsigned int *pix; + + if(XAP > 0){ + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + a = A_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + a += A_VAL(pix) * XAP; + pix += sow; + rr = R_VAL(pix) * XAP; + gg = G_VAL(pix) * XAP; + bb = B_VAL(pix) * XAP; + aa = A_VAL(pix) * XAP; + pix--; + rr += R_VAL(pix) * INV_XAP; + gg += G_VAL(pix) * INV_XAP; + bb += B_VAL(pix) * INV_XAP; + aa += A_VAL(pix) * INV_XAP; + r = ((rr * YAP) + (r * INV_YAP)) >> 16; + g = ((gg * YAP) + (g * INV_YAP)) >> 16; + b = ((bb * YAP) + (b * INV_YAP)) >> 16; + a = ((aa * YAP) + (a * INV_YAP)) >> 16; + *dptr++ = qRgba(r, g, b, a); + } + else{ + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_YAP; + g = G_VAL(pix) * INV_YAP; + b = B_VAL(pix) * INV_YAP; + a = A_VAL(pix) * INV_YAP; + pix += sow; + r += R_VAL(pix) * YAP; + g += G_VAL(pix) * YAP; + b += B_VAL(pix) * YAP; + a += A_VAL(pix) * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + a >>= 8; + *dptr++ = qRgba(r, g, b, a); + } + } + } + else{ + for(x = dxx; x < end; x++){ + int r, g, b, a; + unsigned int *pix; + + if(XAP > 0){ + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + a = A_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + a += A_VAL(pix) * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + a >>= 8; + *dptr++ = qRgba(r, g, b, a); + } + else + *dptr++ = sptr[xpoints[x] ]; + } + } + } + } + /* if we're scaling down vertically */ + else if(isi->xup_yup == 1){ + /*\ 'Correct' version, with math units prepared for MMXification \*/ + int Cy, j; + unsigned int *pix; + int r, g, b, a, rr, gg, bb, aa; + int yap; + + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + Cy = YAP >> 16; + yap = YAP & 0xffff; + + dptr = dest + dx + ((y + dy) * dow); + for(x = dxx; x < end; x++){ + pix = ypoints[dyy + y] + xpoints[x]; + r = (R_VAL(pix) * yap) >> 10; + g = (G_VAL(pix) * yap) >> 10; + b = (B_VAL(pix) * yap) >> 10; + a = (A_VAL(pix) * yap) >> 10; + for(j = (1 << 14) - yap; j > Cy; j -= Cy){ + pix += sow; + r += (R_VAL(pix) * Cy) >> 10; + g += (G_VAL(pix) * Cy) >> 10; + b += (B_VAL(pix) * Cy) >> 10; + a += (A_VAL(pix) * Cy) >> 10; + } + if(j > 0){ + pix += sow; + r += (R_VAL(pix) * j) >> 10; + g += (G_VAL(pix) * j) >> 10; + b += (B_VAL(pix) * j) >> 10; + a += (A_VAL(pix) * j) >> 10; + } + if(XAP > 0){ + pix = ypoints[dyy + y] + xpoints[x] + 1; + rr = (R_VAL(pix) * yap) >> 10; + gg = (G_VAL(pix) * yap) >> 10; + bb = (B_VAL(pix) * yap) >> 10; + aa = (A_VAL(pix) * yap) >> 10; + for(j = (1 << 14) - yap; j > Cy; j -= Cy){ + pix += sow; + rr += (R_VAL(pix) * Cy) >> 10; + gg += (G_VAL(pix) * Cy) >> 10; + bb += (B_VAL(pix) * Cy) >> 10; + aa += (A_VAL(pix) * Cy) >> 10; + } + if(j > 0){ + pix += sow; + rr += (R_VAL(pix) * j) >> 10; + gg += (G_VAL(pix) * j) >> 10; + bb += (B_VAL(pix) * j) >> 10; + aa += (A_VAL(pix) * j) >> 10; + } + r = r * INV_XAP; + g = g * INV_XAP; + b = b * INV_XAP; + a = a * INV_XAP; + r = (r + ((rr * XAP))) >> 12; + g = (g + ((gg * XAP))) >> 12; + b = (b + ((bb * XAP))) >> 12; + a = (a + ((aa * XAP))) >> 12; + } + else{ + r >>= 4; + g >>= 4; + b >>= 4; + a >>= 4; + } + *dptr = qRgba(r, g, b, a); + dptr++; + } + } + } + /* if we're scaling down horizontally */ + else if(isi->xup_yup == 2){ + /*\ 'Correct' version, with math units prepared for MMXification \*/ + int Cx, j; + unsigned int *pix; + int r, g, b, a, rr, gg, bb, aa; + int xap; + + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + dptr = dest + dx + ((y + dy) * dow); + for(x = dxx; x < end; x++){ + Cx = XAP >> 16; + xap = XAP & 0xffff; + + pix = ypoints[dyy + y] + xpoints[x]; + r = (R_VAL(pix) * xap) >> 10; + g = (G_VAL(pix) * xap) >> 10; + b = (B_VAL(pix) * xap) >> 10; + a = (A_VAL(pix) * xap) >> 10; + for(j = (1 << 14) - xap; j > Cx; j -= Cx){ + pix++; + r += (R_VAL(pix) * Cx) >> 10; + g += (G_VAL(pix) * Cx) >> 10; + b += (B_VAL(pix) * Cx) >> 10; + a += (A_VAL(pix) * Cx) >> 10; + } + if(j > 0){ + pix++; + r += (R_VAL(pix) * j) >> 10; + g += (G_VAL(pix) * j) >> 10; + b += (B_VAL(pix) * j) >> 10; + a += (A_VAL(pix) * j) >> 10; + } + if(YAP > 0){ + pix = ypoints[dyy + y] + xpoints[x] + sow; + rr = (R_VAL(pix) * xap) >> 10; + gg = (G_VAL(pix) * xap) >> 10; + bb = (B_VAL(pix) * xap) >> 10; + aa = (A_VAL(pix) * xap) >> 10; + for(j = (1 << 14) - xap; j > Cx; j -= Cx){ + pix++; + rr += (R_VAL(pix) * Cx) >> 10; + gg += (G_VAL(pix) * Cx) >> 10; + bb += (B_VAL(pix) * Cx) >> 10; + aa += (A_VAL(pix) * Cx) >> 10; + } + if(j > 0){ + pix++; + rr += (R_VAL(pix) * j) >> 10; + gg += (G_VAL(pix) * j) >> 10; + bb += (B_VAL(pix) * j) >> 10; + aa += (A_VAL(pix) * j) >> 10; + } + r = r * INV_YAP; + g = g * INV_YAP; + b = b * INV_YAP; + a = a * INV_YAP; + r = (r + ((rr * YAP))) >> 12; + g = (g + ((gg * YAP))) >> 12; + b = (b + ((bb * YAP))) >> 12; + a = (a + ((aa * YAP))) >> 12; + } + else{ + r >>= 4; + g >>= 4; + b >>= 4; + a >>= 4; + } + *dptr = qRgba(r, g, b, a); + dptr++; + } + } + } + /* if we're scaling down horizontally & vertically */ + else{ + /*\ 'Correct' version, with math units prepared for MMXification: + |*| The operation 'b = (b * c) >> 16' translates to pmulhw, + |*| so the operation 'b = (b * c) >> d' would translate to + |*| psllw (16 - d), %mmb; pmulh %mmc, %mmb + \*/ + int Cx, Cy, i, j; + unsigned int *pix; + int a, r, g, b, ax, rx, gx, bx; + int xap, yap; + + for(y = 0; y < dh; y++){ + Cy = YAP >> 16; + yap = YAP & 0xffff; + + dptr = dest + dx + ((y + dy) * dow); + for(x = dxx; x < end; x++){ + Cx = XAP >> 16; + xap = XAP & 0xffff; + + sptr = ypoints[dyy + y] + xpoints[x]; + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + ax = (A_VAL(pix) * xap) >> 9; + pix++; + for(i = (1 << 14) - xap; i > Cx; i -= Cx){ + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + ax += (A_VAL(pix) * Cx) >> 9; + pix++; + } + if(i > 0){ + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + ax += (A_VAL(pix) * i) >> 9; + } + + r = (rx * yap) >> 14; + g = (gx * yap) >> 14; + b = (bx * yap) >> 14; + a = (ax * yap) >> 14; + + for(j = (1 << 14) - yap; j > Cy; j -= Cy){ + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + ax = (A_VAL(pix) * xap) >> 9; + pix++; + for(i = (1 << 14) - xap; i > Cx; i -= Cx){ + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + ax += (A_VAL(pix) * Cx) >> 9; + pix++; + } + if(i > 0){ + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + ax += (A_VAL(pix) * i) >> 9; + } + + r += (rx * Cy) >> 14; + g += (gx * Cy) >> 14; + b += (bx * Cy) >> 14; + a += (ax * Cy) >> 14; + } + if(j > 0){ + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + ax = (A_VAL(pix) * xap) >> 9; + pix++; + for(i = (1 << 14) - xap; i > Cx; i -= Cx){ + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + ax += (A_VAL(pix) * Cx) >> 9; + pix++; + } + if(i > 0){ + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + ax += (A_VAL(pix) * i) >> 9; + } + + r += (rx * j) >> 14; + g += (gx * j) >> 14; + b += (bx * j) >> 14; + a += (ax * j) >> 14; + } + + R_VAL(dptr) = r >> 5; + G_VAL(dptr) = g >> 5; + B_VAL(dptr) = b >> 5; + A_VAL(dptr) = a >> 5; + dptr++; + } + } + } +} + +/* scale by area sampling - IGNORE the ALPHA byte*/ +void MImageScale::mimageScaleAARGB(MImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + unsigned int *sptr, *dptr; + int x, y, end; + unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + end = dxx + dw; + /* scaling up both ways */ + if(isi->xup_yup == 3){ + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + if(YAP > 0){ + for(x = dxx; x < end; x++){ + int r = 0, g = 0, b = 0; + int rr = 0, gg = 0, bb = 0; + unsigned int *pix; + + if(XAP > 0){ + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + pix += sow; + rr = R_VAL(pix) * XAP; + gg = G_VAL(pix) * XAP; + bb = B_VAL(pix) * XAP; + pix --; + rr += R_VAL(pix) * INV_XAP; + gg += G_VAL(pix) * INV_XAP; + bb += B_VAL(pix) * INV_XAP; + r = ((rr * YAP) + (r * INV_YAP)) >> 16; + g = ((gg * YAP) + (g * INV_YAP)) >> 16; + b = ((bb * YAP) + (b * INV_YAP)) >> 16; + *dptr++ = qRgba(r, g, b, 0xff); + } + else{ + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_YAP; + g = G_VAL(pix) * INV_YAP; + b = B_VAL(pix) * INV_YAP; + pix += sow; + r += R_VAL(pix) * YAP; + g += G_VAL(pix) * YAP; + b += B_VAL(pix) * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + *dptr++ = qRgba(r, g, b, 0xff); + } + } + } + else{ + for(x = dxx; x < end; x++){ + int r = 0, g = 0, b = 0; + unsigned int *pix; + + if(XAP > 0){ + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + *dptr++ = qRgba(r, g, b, 0xff); + } + else + *dptr++ = sptr[xpoints[x] ]; + } + } + } + } + /* if we're scaling down vertically */ + else if(isi->xup_yup == 1){ + /*\ 'Correct' version, with math units prepared for MMXification \*/ + int Cy, j; + unsigned int *pix; + int r, g, b, rr, gg, bb; + int yap; + + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + Cy = YAP >> 16; + yap = YAP & 0xffff; + + dptr = dest + dx + ((y + dy) * dow); + for(x = dxx; x < end; x++){ + pix = ypoints[dyy + y] + xpoints[x]; + r = (R_VAL(pix) * yap) >> 10; + g = (G_VAL(pix) * yap) >> 10; + b = (B_VAL(pix) * yap) >> 10; + pix += sow; + for(j = (1 << 14) - yap; j > Cy; j -= Cy){ + r += (R_VAL(pix) * Cy) >> 10; + g += (G_VAL(pix) * Cy) >> 10; + b += (B_VAL(pix) * Cy) >> 10; + pix += sow; + } + if(j > 0){ + r += (R_VAL(pix) * j) >> 10; + g += (G_VAL(pix) * j) >> 10; + b += (B_VAL(pix) * j) >> 10; + } + if(XAP > 0){ + pix = ypoints[dyy + y] + xpoints[x] + 1; + rr = (R_VAL(pix) * yap) >> 10; + gg = (G_VAL(pix) * yap) >> 10; + bb = (B_VAL(pix) * yap) >> 10; + pix += sow; + for(j = (1 << 14) - yap; j > Cy; j -= Cy){ + rr += (R_VAL(pix) * Cy) >> 10; + gg += (G_VAL(pix) * Cy) >> 10; + bb += (B_VAL(pix) * Cy) >> 10; + pix += sow; + } + if(j > 0){ + rr += (R_VAL(pix) * j) >> 10; + gg += (G_VAL(pix) * j) >> 10; + bb += (B_VAL(pix) * j) >> 10; + } + r = r * INV_XAP; + g = g * INV_XAP; + b = b * INV_XAP; + r = (r + ((rr * XAP))) >> 12; + g = (g + ((gg * XAP))) >> 12; + b = (b + ((bb * XAP))) >> 12; + } + else{ + r >>= 4; + g >>= 4; + b >>= 4; + } + *dptr = qRgba(r, g, b, 0xff); + dptr++; + } + } + } + /* if we're scaling down horizontally */ + else if(isi->xup_yup == 2){ + /*\ 'Correct' version, with math units prepared for MMXification \*/ + int Cx, j; + unsigned int *pix; + int r, g, b, rr, gg, bb; + int xap; + + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + dptr = dest + dx + ((y + dy) * dow); + for(x = dxx; x < end; x++){ + Cx = XAP >> 16; + xap = XAP & 0xffff; + + pix = ypoints[dyy + y] + xpoints[x]; + r = (R_VAL(pix) * xap) >> 10; + g = (G_VAL(pix) * xap) >> 10; + b = (B_VAL(pix) * xap) >> 10; + pix++; + for(j = (1 << 14) - xap; j > Cx; j -= Cx){ + r += (R_VAL(pix) * Cx) >> 10; + g += (G_VAL(pix) * Cx) >> 10; + b += (B_VAL(pix) * Cx) >> 10; + pix++; + } + if(j > 0){ + r += (R_VAL(pix) * j) >> 10; + g += (G_VAL(pix) * j) >> 10; + b += (B_VAL(pix) * j) >> 10; + } + if(YAP > 0){ + pix = ypoints[dyy + y] + xpoints[x] + sow; + rr = (R_VAL(pix) * xap) >> 10; + gg = (G_VAL(pix) * xap) >> 10; + bb = (B_VAL(pix) * xap) >> 10; + pix++; + for(j = (1 << 14) - xap; j > Cx; j -= Cx){ + rr += (R_VAL(pix) * Cx) >> 10; + gg += (G_VAL(pix) * Cx) >> 10; + bb += (B_VAL(pix) * Cx) >> 10; + pix++; + } + if(j > 0){ + rr += (R_VAL(pix) * j) >> 10; + gg += (G_VAL(pix) * j) >> 10; + bb += (B_VAL(pix) * j) >> 10; + } + r = r * INV_YAP; + g = g * INV_YAP; + b = b * INV_YAP; + r = (r + ((rr * YAP))) >> 12; + g = (g + ((gg * YAP))) >> 12; + b = (b + ((bb * YAP))) >> 12; + } + else{ + r >>= 4; + g >>= 4; + b >>= 4; + } + *dptr = qRgba(r, g, b, 0xff); + dptr++; + } + } + } + /* fully optimized (i think) - onyl change of algorithm can help */ + /* if we're scaling down horizontally & vertically */ + else{ + /*\ 'Correct' version, with math units prepared for MMXification \*/ + int Cx, Cy, i, j; + unsigned int *pix; + int r, g, b, rx, gx, bx; + int xap, yap; + + for(y = 0; y < dh; y++){ + Cy = YAP >> 16; + yap = YAP & 0xffff; + + dptr = dest + dx + ((y + dy) * dow); + for(x = dxx; x < end; x++){ + Cx = XAP >> 16; + xap = XAP & 0xffff; + + sptr = ypoints[dyy + y] + xpoints[x]; + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + pix++; + for(i = (1 << 14) - xap; i > Cx; i -= Cx){ + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + pix++; + } + if(i > 0){ + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + } + + r = (rx * yap) >> 14; + g = (gx * yap) >> 14; + b = (bx * yap) >> 14; + + for(j = (1 << 14) - yap; j > Cy; j -= Cy){ + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + pix++; + for(i = (1 << 14) - xap; i > Cx; i -= Cx){ + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + pix++; + } + if(i > 0){ + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + } + + r += (rx * Cy) >> 14; + g += (gx * Cy) >> 14; + b += (bx * Cy) >> 14; + } + if(j > 0){ + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + pix++; + for(i = (1 << 14) - xap; i > Cx; i -= Cx){ + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + pix++; + } + if(i > 0){ + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + } + + r += (rx * j) >> 14; + g += (gx * j) >> 14; + b += (bx * j) >> 14; + } + + R_VAL(dptr) = r >> 5; + G_VAL(dptr) = g >> 5; + B_VAL(dptr) = b >> 5; + dptr++; + } + } + } +} + +// Imlib2/Mosfet code end + + +// public functions : +// ------------------ + +// This function returns how many pixels around the zoomed area should be +// included in the image. This is used when doing incremental painting, because +// some smoothing algorithms use surrounding pixels and not including them +// could sometimes make the edges between incremental steps visible. +int extraScalePixels( SmoothAlgorithm alg, double zoom, double blur ) +{ + double filtersupport = 0; + Filter filter = NULL; + switch( alg ) { + case SMOOTH_NONE: + filter = NULL; + filtersupport = 0.0; + break; + case SMOOTH_FAST: + filter = Box; + filtersupport = 0.5; + break; + case SMOOTH_NORMAL: + filter = Triangle; + filtersupport = 1.0; + break; + case SMOOTH_BEST: +// filter = Mitchell; + filter = Bicubic; + filtersupport = 2.0; + break; + } + if( zoom == 1.0 || filtersupport == 0.0 ) return 0; + // Imlib2/Mosfet scale - I have really no idea how many pixels it needs + if( filter == Box && blur == 1.0 ) return int( 3 / zoom + 1 ); +// This is support size for ImageMagick's scaling. + double scale=blur*QMAX(1.0/zoom,1.0); + double support=scale* filtersupport; + if (support <= 0.5) support=0.5+0.000001; + return int( support + 1 ); +} + +QImage scale(const QImage& image, int width, int height, + SmoothAlgorithm alg, QImage::ScaleMode mode, double blur ) +{ + if( image.isNull()) return image.copy(); + + QSize newSize( image.size() ); + newSize.scale( QSize( width, height ), (QSize::ScaleMode)mode ); // ### remove cast in Qt 4.0 + newSize = newSize.expandedTo( QSize( 1, 1 )); // make sure it doesn't become null + + if ( newSize == image.size() ) return image.copy(); + + width = newSize.width(); + height = newSize.height(); + Filter filter = NULL; + fastfloat filtersupport; + + switch( alg ) { + case SMOOTH_NONE: + filter = NULL; + filtersupport = 0.0; + break; + case SMOOTH_FAST: + filter = Box; + filtersupport = 0.5; + break; + case SMOOTH_NORMAL: + default: + filter = Triangle; + filtersupport = 1.0; + break; + case SMOOTH_BEST: +// filter = Mitchell; + filter = Bicubic; + filtersupport = 2.0; + break; + } + + if( filter == Box && blur == 1.0 ) + return MImageScale::smoothScale( image, width, height ); + + if( filter == Box && width > image.width() && height > image.height() && blur == 1.0 ) { + filter = NULL; // Box doesn't really smooth when enlarging + } + + if( filter == NULL ) { + return SampleImage( image, width, height ); // doesn't need 32bit + } + + return ResizeImage( image.convertDepth( 32 ), width, height, filter, filtersupport, blur ); + // unlike Qt's smoothScale() this function introduces new colors to grayscale images ... oh well +} + + +} // namespace diff --git a/src/imageutils/testjpegcontent.cpp b/src/imageutils/testjpegcontent.cpp new file mode 100644 index 0000000..b533373 --- /dev/null +++ b/src/imageutils/testjpegcontent.cpp @@ -0,0 +1,256 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include + +// Qt +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include + +// Local +#include "imageutils/imageutils.h" +#include "imageutils/jpegcontent.h" + +using namespace std; + +const char* ORIENT6_FILE="orient6.jpg"; +const int ORIENT6_WIDTH=128; // This size is the size *after* orientation +const int ORIENT6_HEIGHT=256; // has been applied +const char* CUT_FILE="cut.jpg"; +const QString ORIENT6_COMMENT="a comment"; +const QString ORIENT1_VFLIP_FILE="test_orient1_vflip.jpg"; +const char* THUMBNAIL_FILE="test_thumbnail.jpg"; +const char* TMP_FILE="tmp.jpg"; + + +class TestEnvironment { +public: + TestEnvironment() { + bool result; + QFile in(ORIENT6_FILE); + result=in.open(IO_ReadOnly); + Q_ASSERT(result); + + QFileInfo info(in); + int size=info.size()/2; + + char* data=new char[size]; + int readSize=in.readBlock(data, size); + Q_ASSERT(size==readSize); + + QFile out(CUT_FILE); + result=out.open(IO_WriteOnly); + Q_ASSERT(result); + + int wroteSize=out.writeBlock(data, size); + Q_ASSERT(size==wroteSize); + delete []data; + } + + ~TestEnvironment() { + QDir::current().remove(CUT_FILE); + } +}; + + +typedef QMap MetaInfoMap; + +MetaInfoMap getMetaInfo(const QString& path) { + KFileMetaInfo fmi(path); + QStringList list=fmi.supportedKeys(); + QStringList::ConstIterator it=list.begin(); + MetaInfoMap map; + + for ( ; it!=list.end(); ++it) { + KFileMetaInfoItem item=fmi.item(*it); + map[*it]=item.string(); + } + + return map; +} + +void compareMetaInfo(const QString& path1, const QString& path2, const QStringList& ignoredKeys) { + MetaInfoMap mim1=getMetaInfo(path1); + MetaInfoMap mim2=getMetaInfo(path2); + + Q_ASSERT(mim1.keys()==mim2.keys()); + QValueList keys=mim1.keys(); + QValueList::ConstIterator it=keys.begin(); + for ( ; it!=keys.end(); ++it) { + QString key=*it; + if (ignoredKeys.contains(key)) continue; + + if (mim1[key]!=mim2[key]) { + kdError() << "Meta info differs. Key:" << key << ", V1:" << mim1[key] << ", V2:" << mim2[key] << endl; + } + } +} + + +void testResetOrientation() { + ImageUtils::JPEGContent content; + bool result; + + // Test resetOrientation without transform + result=content.load(ORIENT6_FILE); + Q_ASSERT(result); + + content.resetOrientation(); + + result=content.save(TMP_FILE); + Q_ASSERT(result); + + result=content.load(TMP_FILE); + Q_ASSERT(result); + Q_ASSERT(content.orientation() == ImageUtils::NORMAL); + + // Test resetOrientation with transform + result=content.load(ORIENT6_FILE); + Q_ASSERT(result); + + content.resetOrientation(); + content.transform(ImageUtils::ROT_90); + + result=content.save(TMP_FILE); + Q_ASSERT(result); + + result=content.load(TMP_FILE); + Q_ASSERT(result); + Q_ASSERT(content.orientation() == ImageUtils::NORMAL); +} + + +/** + * This function tests JPEGContent::transform() by applying a ROT_90 + * transformation, saving, reloading and applying a ROT_270 to undo the ROT_90. + * Saving and reloading are necessary because lossless transformation only + * happens in JPEGContent::save() + */ +void testTransform() { + bool result; + QImage finalImage, expectedImage; + + ImageUtils::JPEGContent content; + result = content.load(ORIENT6_FILE); + Q_ASSERT(result); + + content.transform(ImageUtils::ROT_90); + result = content.save(TMP_FILE); + Q_ASSERT(result); + + result = content.load(TMP_FILE); + Q_ASSERT(result); + content.transform(ImageUtils::ROT_270); + result = content.save(TMP_FILE); + Q_ASSERT(result); + + result = finalImage.load(TMP_FILE); + Q_ASSERT(result); + + result = expectedImage.load(ORIENT6_FILE); + Q_ASSERT(result); + + Q_ASSERT(finalImage == expectedImage); +} + + +void testSetComment() { + QString comment = "test comment"; + ImageUtils::JPEGContent content; + bool result; + result = content.load(ORIENT6_FILE); + Q_ASSERT(result); + + content.setComment(comment); + Q_ASSERT(content.comment() == comment); + result = content.save(TMP_FILE); + Q_ASSERT(result); + + result = content.load(TMP_FILE); + Q_ASSERT(result); + Q_ASSERT(content.comment() == comment); +} + + +int main(int argc, char* argv[]) { + TestEnvironment testEnv; + bool result; + KAboutData aboutData("testjpegcontent", "testjpegcontent", "0"); + KCmdLineArgs::init( argc, argv, &aboutData ); + KApplication kapplication; + + // Reading info + ImageUtils::JPEGContent content; + result=content.load(ORIENT6_FILE); + Q_ASSERT(result); + Q_ASSERT(content.orientation() == 6); + Q_ASSERT(content.comment() == ORIENT6_COMMENT); + Q_ASSERT(content.size() == QSize(ORIENT6_WIDTH, ORIENT6_HEIGHT)); + + // thumbnail() + QImage thumbnail=content.thumbnail(); + result=thumbnail.save(THUMBNAIL_FILE, "JPEG"); + Q_ASSERT(result); + + testResetOrientation(); + testTransform(); + testSetComment(); + + // Test that rotating a file a lot of times does not cause findJxform() to fail + result = content.load(ORIENT6_FILE); + Q_ASSERT(result); + + // 12*4 + 1 is the same as 1, since rotating four times brings you back + for(int loop=0; loop< 12*4 + 1; ++loop) { + content.transform(ImageUtils::ROT_90); + } + result = content.save(TMP_FILE); + Q_ASSERT(result); + + result = content.load(TMP_FILE); + Q_ASSERT(result); + + Q_ASSERT(content.size() == QSize(ORIENT6_HEIGHT, ORIENT6_WIDTH)); + + + // Check the other meta info are still here + QStringList ignoredKeys; + ignoredKeys << "Orientation" << "Comment"; + compareMetaInfo(ORIENT6_FILE, ORIENT1_VFLIP_FILE, ignoredKeys); + + // Test that loading and manipulating a truncated file does not crash + result=content.load(CUT_FILE); + Q_ASSERT(result); + Q_ASSERT(content.orientation() == 6); + Q_ASSERT(content.comment() == ORIENT6_COMMENT); + content.transform(ImageUtils::VFLIP); + kdWarning() << "# Next function should output errors about incomplete image" << endl; + content.save(TMP_FILE); + kdWarning() << "#" << endl; +} diff --git a/src/imageutils/transupp.c b/src/imageutils/transupp.c new file mode 100644 index 0000000..e5ec564 --- /dev/null +++ b/src/imageutils/transupp.c @@ -0,0 +1,928 @@ +/* + * transupp.c + * + * Copyright (C) 1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains image transformation routines and other utility code + * used by the jpegtran sample application. These are NOT part of the core + * JPEG library. But we keep these routines separate from jpegtran.c to + * ease the task of maintaining jpegtran-like programs that have other user + * interfaces. + */ + +/* Although this file really shouldn't have access to the library internals, + * it's helpful to let it call jround_up() and jcopy_block_row(). + */ +#define JPEG_INTERNALS + +#include "jinclude.h" +#include "jpeglib.h" +#include "transupp.h" /* My own external interface */ + + +#if TRANSFORMS_SUPPORTED + +/* + * Lossless image transformation routines. These routines work on DCT + * coefficient arrays and thus do not require any lossy decompression + * or recompression of the image. + * Thanks to Guido Vollbeding for the initial design and code of this feature. + * + * Horizontal flipping is done in-place, using a single top-to-bottom + * pass through the virtual source array. It will thus be much the + * fastest option for images larger than main memory. + * + * The other routines require a set of destination virtual arrays, so they + * need twice as much memory as jpegtran normally does. The destination + * arrays are always written in normal scan order (top to bottom) because + * the virtual array manager expects this. The source arrays will be scanned + * in the corresponding order, which means multiple passes through the source + * arrays for most of the transforms. That could result in much thrashing + * if the image is larger than main memory. + * + * Some notes about the operating environment of the individual transform + * routines: + * 1. Both the source and destination virtual arrays are allocated from the + * source JPEG object, and therefore should be manipulated by calling the + * source's memory manager. + * 2. The destination's component count should be used. It may be smaller + * than the source's when forcing to grayscale. + * 3. Likewise the destination's sampling factors should be used. When + * forcing to grayscale the destination's sampling factors will be all 1, + * and we may as well take that as the effective iMCU size. + * 4. When "trim" is in effect, the destination's dimensions will be the + * trimmed values but the source's will be untrimmed. + * 5. All the routines assume that the source and destination buffers are + * padded out to a full iMCU boundary. This is true, although for the + * source buffer it is an undocumented property of jdcoefct.c. + * Notes 2,3,4 boil down to this: generally we should use the destination's + * dimensions and ignore the source's. + */ + + +LOCAL(void) +do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays) +/* Horizontal flip; done in-place, so no separate dest array is required */ +{ + JDIMENSION MCU_cols, comp_width, blk_x, blk_y; + int ci, k, offset_y; + JBLOCKARRAY buffer; + JCOEFPTR ptr1, ptr2; + JCOEF temp1, temp2; + jpeg_component_info *compptr; + + /* Horizontal mirroring of DCT blocks is accomplished by swapping + * pairs of blocks in-place. Within a DCT block, we perform horizontal + * mirroring by changing the signs of odd-numbered columns. + * Partial iMCUs at the right edge are left untouched. + */ + MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + for (blk_y = 0; blk_y < compptr->height_in_blocks; + blk_y += compptr->v_samp_factor) { + buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { + ptr1 = buffer[offset_y][blk_x]; + ptr2 = buffer[offset_y][comp_width - blk_x - 1]; + /* this unrolled loop doesn't need to know which row it's on... */ + for (k = 0; k < DCTSIZE2; k += 2) { + temp1 = *ptr1; /* swap even column */ + temp2 = *ptr2; + *ptr1++ = temp2; + *ptr2++ = temp1; + temp1 = *ptr1; /* swap odd column with sign change */ + temp2 = *ptr2; + *ptr1++ = -temp2; + *ptr2++ = -temp1; + } + } + } + } + } +} + + +LOCAL(void) +do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Vertical flip */ +{ + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* We output into a separate array because we can't touch different + * rows of the source virtual array simultaneously. Otherwise, this + * is a pretty straightforward analog of horizontal flip. + * Within a DCT block, vertical mirroring is done by changing the signs + * of odd-numbered rows. + * Partial iMCUs at the bottom edge are copied verbatim. + */ + MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge blocks will be copied verbatim. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + if (dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[dst_blk_x]; + for (i = 0; i < DCTSIZE; i += 2) { + /* copy even row */ + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = *src_ptr++; + /* copy odd row with sign change */ + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = - *src_ptr++; + } + } + } else { + /* Just copy row verbatim. */ + jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y], + compptr->width_in_blocks); + } + } + } + } +} + + +LOCAL(void) +do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Transpose source into destination */ +{ + JDIMENSION dst_blk_x, dst_blk_y; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Transposing pixels within a block just requires transposing the + * DCT coefficients. + * Partial iMCUs at the edges require no special treatment; we simply + * process all the available DCT blocks for every component. + */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } +} + + +LOCAL(void) +do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 90 degree rotation is equivalent to + * 1. Transposing the image; + * 2. Horizontal mirroring. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Because of the horizontal mirror step, we can't process partial iMCUs + * at the (output) right edge properly. They just get transposed and + * not mirrored. + */ + MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + if (dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + dst_ptr = dst_buffer[offset_y] + [comp_width - dst_blk_x - offset_x - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + i++; + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } else { + /* Edge blocks are transposed but not mirrored. */ + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } +} + + +LOCAL(void) +do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 270 degree rotation is equivalent to + * 1. Horizontal mirroring; + * 2. Transposing the image. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Because of the horizontal mirror step, we can't process partial iMCUs + * at the (output) bottom edge properly. They just get transposed and + * not mirrored. + */ + MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + if (dst_blk_y < comp_height) { + /* Block is within the mirrorable area. */ + src_ptr = src_buffer[offset_x] + [comp_height - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } + } else { + /* Edge blocks are transposed but not mirrored. */ + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } +} + + +LOCAL(void) +do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 180 degree rotation is equivalent to + * 1. Vertical mirroring; + * 2. Horizontal mirroring. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (dst_blk_y < comp_height) { + /* Row is within the vertically mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge rows are only mirrored horizontally. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + if (dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; + /* Process the blocks that can be mirrored both ways. */ + for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; + for (i = 0; i < DCTSIZE; i += 2) { + /* For even row, negate every odd column. */ + for (j = 0; j < DCTSIZE; j += 2) { + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = - *src_ptr++; + } + /* For odd row, negate every even column. */ + for (j = 0; j < DCTSIZE; j += 2) { + *dst_ptr++ = - *src_ptr++; + *dst_ptr++ = *src_ptr++; + } + } + } + /* Any remaining right-edge blocks are only mirrored vertically. */ + for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[dst_blk_x]; + for (i = 0; i < DCTSIZE; i += 2) { + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = *src_ptr++; + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = - *src_ptr++; + } + } + } else { + /* Remaining rows are just mirrored horizontally. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[offset_y]; + /* Process the blocks that can be mirrored. */ + for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; + for (i = 0; i < DCTSIZE2; i += 2) { + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = - *src_ptr++; + } + } + /* Any remaining right-edge blocks are only copied. */ + for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[dst_blk_x]; + for (i = 0; i < DCTSIZE2; i++) + *dst_ptr++ = *src_ptr++; + } + } + } + } + } +} + + +LOCAL(void) +do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Transverse transpose is equivalent to + * 1. 180 degree rotation; + * 2. Transposition; + * or + * 1. Horizontal mirroring; + * 2. Transposition; + * 3. Horizontal mirroring. + * These steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + if (dst_blk_y < comp_height) { + src_ptr = src_buffer[offset_x] + [comp_height - dst_blk_y - offset_y - 1]; + if (dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + dst_ptr = dst_buffer[offset_y] + [comp_width - dst_blk_x - offset_x - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + i++; + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } else { + /* Right-edge blocks are mirrored in y only */ + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } + } + } else { + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + if (dst_blk_x < comp_width) { + /* Bottom-edge blocks are mirrored in x only */ + dst_ptr = dst_buffer[offset_y] + [comp_width - dst_blk_x - offset_x - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + i++; + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } else { + /* At lower right corner, just transpose, no mirroring */ + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } + } +} + + +/* Request any required workspace. + * + * We allocate the workspace virtual arrays from the source decompression + * object, so that all the arrays (both the original data and the workspace) + * will be taken into account while making memory management decisions. + * Hence, this routine must be called after jpeg_read_header (which reads + * the image dimensions) and before jpeg_read_coefficients (which realizes + * the source's virtual arrays). + */ + +GLOBAL(void) +jtransform_request_workspace (j_decompress_ptr srcinfo, + jpeg_transform_info *info) +{ + jvirt_barray_ptr *coef_arrays = NULL; + jpeg_component_info *compptr; + int ci; + + if (info->force_grayscale && + srcinfo->jpeg_color_space == JCS_YCbCr && + srcinfo->num_components == 3) { + /* We'll only process the first component */ + info->num_components = 1; + } else { + /* Process all the components */ + info->num_components = srcinfo->num_components; + } + + switch (info->transform) { + case JXFORM_NONE: + case JXFORM_FLIP_H: + /* Don't need a workspace array */ + break; + case JXFORM_FLIP_V: + case JXFORM_ROT_180: + /* Need workspace arrays having same dimensions as source image. + * Note that we allocate arrays padded out to the next iMCU boundary, + * so that transform routines need not worry about missing edge blocks. + */ + coef_arrays = (jvirt_barray_ptr *) + (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, + SIZEOF(jvirt_barray_ptr) * info->num_components); + for (ci = 0; ci < info->num_components; ci++) { + compptr = srcinfo->comp_info + ci; + coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) + ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } + break; + case JXFORM_TRANSPOSE: + case JXFORM_TRANSVERSE: + case JXFORM_ROT_90: + case JXFORM_ROT_270: + /* Need workspace arrays having transposed dimensions. + * Note that we allocate arrays padded out to the next iMCU boundary, + * so that transform routines need not worry about missing edge blocks. + */ + coef_arrays = (jvirt_barray_ptr *) + (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, + SIZEOF(jvirt_barray_ptr) * info->num_components); + for (ci = 0; ci < info->num_components; ci++) { + compptr = srcinfo->comp_info + ci; + coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) + ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) compptr->h_samp_factor); + } + break; + } + info->workspace_coef_arrays = coef_arrays; +} + + +/* Transpose destination image parameters */ + +LOCAL(void) +transpose_critical_parameters (j_compress_ptr dstinfo) +{ + int tblno, i, j, ci, itemp; + jpeg_component_info *compptr; + JQUANT_TBL *qtblptr; + JDIMENSION dtemp; + UINT16 qtemp; + + /* Transpose basic image dimensions */ + dtemp = dstinfo->image_width; + dstinfo->image_width = dstinfo->image_height; + dstinfo->image_height = dtemp; + + /* Transpose sampling factors */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + itemp = compptr->h_samp_factor; + compptr->h_samp_factor = compptr->v_samp_factor; + compptr->v_samp_factor = itemp; + } + + /* Transpose quantization tables */ + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + qtblptr = dstinfo->quant_tbl_ptrs[tblno]; + if (qtblptr != NULL) { + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < i; j++) { + qtemp = qtblptr->quantval[i*DCTSIZE+j]; + qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; + qtblptr->quantval[j*DCTSIZE+i] = qtemp; + } + } + } + } +} + + +/* Trim off any partial iMCUs on the indicated destination edge */ + +LOCAL(void) +trim_right_edge (j_compress_ptr dstinfo) +{ + int ci, max_h_samp_factor; + JDIMENSION MCU_cols; + + /* We have to compute max_h_samp_factor ourselves, + * because it hasn't been set yet in the destination + * (and we don't want to use the source's value). + */ + max_h_samp_factor = 1; + for (ci = 0; ci < dstinfo->num_components; ci++) { + int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor; + max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor); + } + MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE); + if (MCU_cols > 0) /* can't trim to 0 pixels */ + dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE); +} + +LOCAL(void) +trim_bottom_edge (j_compress_ptr dstinfo) +{ + int ci, max_v_samp_factor; + JDIMENSION MCU_rows; + + /* We have to compute max_v_samp_factor ourselves, + * because it hasn't been set yet in the destination + * (and we don't want to use the source's value). + */ + max_v_samp_factor = 1; + for (ci = 0; ci < dstinfo->num_components; ci++) { + int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor; + max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor); + } + MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE); + if (MCU_rows > 0) /* can't trim to 0 pixels */ + dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE); +} + + +/* Adjust output image parameters as needed. + * + * This must be called after jpeg_copy_critical_parameters() + * and before jpeg_write_coefficients(). + * + * The return value is the set of virtual coefficient arrays to be written + * (either the ones allocated by jtransform_request_workspace, or the + * original source data arrays). The caller will need to pass this value + * to jpeg_write_coefficients(). + */ + +GLOBAL(jvirt_barray_ptr *) +jtransform_adjust_parameters (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info) +{ + /* If force-to-grayscale is requested, adjust destination parameters */ + if (info->force_grayscale) { + /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed + * properly. Among other things, the target h_samp_factor & v_samp_factor + * will get set to 1, which typically won't match the source. + * In fact we do this even if the source is already grayscale; that + * provides an easy way of coercing a grayscale JPEG with funny sampling + * factors to the customary 1,1. (Some decoders fail on other factors.) + */ + if ((dstinfo->jpeg_color_space == JCS_YCbCr && + dstinfo->num_components == 3) || + (dstinfo->jpeg_color_space == JCS_GRAYSCALE && + dstinfo->num_components == 1)) { + /* We have to preserve the source's quantization table number. */ + int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; + jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); + dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; + } else { + /* Sorry, can't do it */ + ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); + } + } + + /* Correct the destination's image dimensions etc if necessary */ + switch (info->transform) { + case JXFORM_NONE: + /* Nothing to do */ + break; + case JXFORM_FLIP_H: + if (info->trim) + trim_right_edge(dstinfo); + break; + case JXFORM_FLIP_V: + if (info->trim) + trim_bottom_edge(dstinfo); + break; + case JXFORM_TRANSPOSE: + transpose_critical_parameters(dstinfo); + /* transpose does NOT have to trim anything */ + break; + case JXFORM_TRANSVERSE: + transpose_critical_parameters(dstinfo); + if (info->trim) { + trim_right_edge(dstinfo); + trim_bottom_edge(dstinfo); + } + break; + case JXFORM_ROT_90: + transpose_critical_parameters(dstinfo); + if (info->trim) + trim_right_edge(dstinfo); + break; + case JXFORM_ROT_180: + if (info->trim) { + trim_right_edge(dstinfo); + trim_bottom_edge(dstinfo); + } + break; + case JXFORM_ROT_270: + transpose_critical_parameters(dstinfo); + if (info->trim) + trim_bottom_edge(dstinfo); + break; + } + + /* Return the appropriate output data set */ + if (info->workspace_coef_arrays != NULL) + return info->workspace_coef_arrays; + return src_coef_arrays; +} + + +/* Execute the actual transformation, if any. + * + * This must be called *after* jpeg_write_coefficients, because it depends + * on jpeg_write_coefficients to have computed subsidiary values such as + * the per-component width and height fields in the destination object. + * + * Note that some transformations will modify the source data arrays! + */ + +GLOBAL(void) +jtransform_execute_transformation (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info) +{ + jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; + + switch (info->transform) { + case JXFORM_NONE: + break; + case JXFORM_FLIP_H: + do_flip_h(srcinfo, dstinfo, src_coef_arrays); + break; + case JXFORM_FLIP_V: + do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSPOSE: + do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSVERSE: + do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_90: + do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_180: + do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_270: + do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + } +} + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* Setup decompression object to save desired markers in memory. + * This must be called before jpeg_read_header() to have the desired effect. + */ + +GLOBAL(void) +jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) +{ +#ifdef SAVE_MARKERS_SUPPORTED + int m; + + /* Save comments except under NONE option */ + if (option != JCOPYOPT_NONE) { + jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); + } + /* Save all types of APPn markers iff ALL option */ + if (option == JCOPYOPT_ALL) { + for (m = 0; m < 16; m++) + jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); + } +#endif /* SAVE_MARKERS_SUPPORTED */ +} + +/* Copy markers saved in the given source object to the destination object. + * This should be called just after jpeg_start_compress() or + * jpeg_write_coefficients(). + * Note that those routines will have written the SOI, and also the + * JFIF APP0 or Adobe APP14 markers if selected. + */ + +GLOBAL(void) +jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option) +{ + jpeg_saved_marker_ptr marker; + + /* In the current implementation, we don't actually need to examine the + * option flag here; we just copy everything that got saved. + * But to avoid confusion, we do not output JFIF and Adobe APP14 markers + * if the encoder library already wrote one. + */ + for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { + if (dstinfo->write_JFIF_header && + marker->marker == JPEG_APP0 && + marker->data_length >= 5 && + GETJOCTET(marker->data[0]) == 0x4A && + GETJOCTET(marker->data[1]) == 0x46 && + GETJOCTET(marker->data[2]) == 0x49 && + GETJOCTET(marker->data[3]) == 0x46 && + GETJOCTET(marker->data[4]) == 0) + continue; /* reject duplicate JFIF */ + if (dstinfo->write_Adobe_marker && + marker->marker == JPEG_APP0+14 && + marker->data_length >= 5 && + GETJOCTET(marker->data[0]) == 0x41 && + GETJOCTET(marker->data[1]) == 0x64 && + GETJOCTET(marker->data[2]) == 0x6F && + GETJOCTET(marker->data[3]) == 0x62 && + GETJOCTET(marker->data[4]) == 0x65) + continue; /* reject duplicate Adobe */ +#ifdef NEED_FAR_POINTERS + /* We could use jpeg_write_marker if the data weren't FAR... */ + { + unsigned int i; + jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); + for (i = 0; i < marker->data_length; i++) + jpeg_write_m_byte(dstinfo, marker->data[i]); + } +#else + jpeg_write_marker(dstinfo, marker->marker, + marker->data, marker->data_length); +#endif + } +} diff --git a/src/imageutils/transupp.h b/src/imageutils/transupp.h new file mode 100644 index 0000000..c4292b5 --- /dev/null +++ b/src/imageutils/transupp.h @@ -0,0 +1,141 @@ +/* + * transupp.h + * + * Copyright (C) 1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for image transformation routines and + * other utility code used by the jpegtran sample application. These are + * NOT part of the core JPEG library. But we keep these routines separate + * from jpegtran.c to ease the task of maintaining jpegtran-like programs + * that have other user interfaces. + * + * NOTE: all the routines declared here have very specific requirements + * about when they are to be executed during the reading and writing of the + * source and destination files. See the comments in transupp.c, or see + * jpegtran.c for an example of correct usage. + */ + +#ifndef TRANSUPP_H +#define TRANSUPP_H + +/* If you happen not to want the image transform support, disable it here */ +#ifndef TRANSFORMS_SUPPORTED +#define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ +#endif + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jtransform_request_workspace jTrRequest +#define jtransform_adjust_parameters jTrAdjust +#define jtransform_execute_transformation jTrExec +#define jcopy_markers_setup jCMrkSetup +#define jcopy_markers_execute jCMrkExec +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * Codes for supported types of image transformations. + */ + +typedef enum { + JXFORM_NONE, /* no transformation */ + JXFORM_FLIP_H, /* horizontal flip */ + JXFORM_FLIP_V, /* vertical flip */ + JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ + JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ + JXFORM_ROT_90, /* 90-degree clockwise rotation */ + JXFORM_ROT_180, /* 180-degree rotation */ + JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ +} JXFORM_CODE; + +/* + * Although rotating and flipping data expressed as DCT coefficients is not + * hard, there is an asymmetry in the JPEG format specification for images + * whose dimensions aren't multiples of the iMCU size. The right and bottom + * image edges are padded out to the next iMCU boundary with junk data; but + * no padding is possible at the top and left edges. If we were to flip + * the whole image including the pad data, then pad garbage would become + * visible at the top and/or left, and real pixels would disappear into the + * pad margins --- perhaps permanently, since encoders & decoders may not + * bother to preserve DCT blocks that appear to be completely outside the + * nominal image area. So, we have to exclude any partial iMCUs from the + * basic transformation. + * + * Transpose is the only transformation that can handle partial iMCUs at the + * right and bottom edges completely cleanly. flip_h can flip partial iMCUs + * at the bottom, but leaves any partial iMCUs at the right edge untouched. + * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. + * The other transforms are defined as combinations of these basic transforms + * and process edge blocks in a way that preserves the equivalence. + * + * The "trim" option causes untransformable partial iMCUs to be dropped; + * this is not strictly lossless, but it usually gives the best-looking + * result for odd-size images. Note that when this option is active, + * the expected mathematical equivalences between the transforms may not hold. + * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim + * followed by -rot 180 -trim trims both edges.) + * + * We also offer a "force to grayscale" option, which simply discards the + * chrominance channels of a YCbCr image. This is lossless in the sense that + * the luminance channel is preserved exactly. It's not the same kind of + * thing as the rotate/flip transformations, but it's convenient to handle it + * as part of this package, mainly because the transformation routines have to + * be aware of the option to know how many components to work on. + */ + +typedef struct { + /* Options: set by caller */ + JXFORM_CODE transform; /* image transform operator */ + boolean trim; /* if TRUE, trim partial MCUs as needed */ + boolean force_grayscale; /* if TRUE, convert color image to grayscale */ + + /* Internal workspace: caller should not touch these */ + int num_components; /* # of components in workspace */ + jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ +} jpeg_transform_info; + + +#if TRANSFORMS_SUPPORTED + +/* Request any required workspace */ +EXTERN(void) jtransform_request_workspace + JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); +/* Adjust output image parameters */ +EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); +/* Execute the actual transformation, if any */ +EXTERN(void) jtransform_execute_transformation + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* + * Support for copying optional markers from source to destination file. + */ + +typedef enum { + JCOPYOPT_NONE, /* copy no optional markers */ + JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ + JCOPYOPT_ALL /* copy all optional markers */ +} JCOPY_OPTION; + +#define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ + +/* Setup decompression object to save desired markers in memory */ +EXTERN(void) jcopy_markers_setup + JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); +/* Copy markers saved in the given source object to the destination object */ +EXTERN(void) jcopy_markers_execute + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option)); + +#endif + diff --git a/src/pics/Makefile.am b/src/pics/Makefile.am new file mode 100644 index 0000000..e52ab4c --- /dev/null +++ b/src/pics/Makefile.am @@ -0,0 +1 @@ +SUBDIRS=action app cursor thumbnail diff --git a/src/pics/action/Makefile.am b/src/pics/action/Makefile.am new file mode 100644 index 0000000..fe4963d --- /dev/null +++ b/src/pics/action/Makefile.am @@ -0,0 +1,2 @@ +icondir = $(kde_datadir)/gwenview/icons +icon_ICON = AUTO diff --git a/src/pics/action/hi16-action-dnd1.png b/src/pics/action/hi16-action-dnd1.png new file mode 100644 index 0000000..60f9594 Binary files /dev/null and b/src/pics/action/hi16-action-dnd1.png differ diff --git a/src/pics/action/hi16-action-dnd2.png b/src/pics/action/hi16-action-dnd2.png new file mode 100644 index 0000000..fc70f77 Binary files /dev/null and b/src/pics/action/hi16-action-dnd2.png differ diff --git a/src/pics/action/hi16-action-dnd3.png b/src/pics/action/hi16-action-dnd3.png new file mode 100644 index 0000000..942ad5f Binary files /dev/null and b/src/pics/action/hi16-action-dnd3.png differ diff --git a/src/pics/action/hi16-action-dnd4.png b/src/pics/action/hi16-action-dnd4.png new file mode 100644 index 0000000..fc70f77 Binary files /dev/null and b/src/pics/action/hi16-action-dnd4.png differ diff --git a/src/pics/action/hi16-action-dnd5.png b/src/pics/action/hi16-action-dnd5.png new file mode 100644 index 0000000..da740a7 Binary files /dev/null and b/src/pics/action/hi16-action-dnd5.png differ diff --git a/src/pics/action/hi16-action-dnd6.png b/src/pics/action/hi16-action-dnd6.png new file mode 100644 index 0000000..c7e6605 Binary files /dev/null and b/src/pics/action/hi16-action-dnd6.png differ diff --git a/src/pics/action/hi16-action-dnd7.png b/src/pics/action/hi16-action-dnd7.png new file mode 100644 index 0000000..4911557 Binary files /dev/null and b/src/pics/action/hi16-action-dnd7.png differ diff --git a/src/pics/action/hi16-action-dnd8.png b/src/pics/action/hi16-action-dnd8.png new file mode 100644 index 0000000..77c6371 Binary files /dev/null and b/src/pics/action/hi16-action-dnd8.png differ diff --git a/src/pics/action/hi16-action-flip.png b/src/pics/action/hi16-action-flip.png new file mode 100644 index 0000000..3481a3c Binary files /dev/null and b/src/pics/action/hi16-action-flip.png differ diff --git a/src/pics/action/hi16-action-mirror.png b/src/pics/action/hi16-action-mirror.png new file mode 100644 index 0000000..7942f3f Binary files /dev/null and b/src/pics/action/hi16-action-mirror.png differ diff --git a/src/pics/action/hi16-action-rotate_left.png b/src/pics/action/hi16-action-rotate_left.png new file mode 100644 index 0000000..0c138a9 Binary files /dev/null and b/src/pics/action/hi16-action-rotate_left.png differ diff --git a/src/pics/action/hi16-action-rotate_right.png b/src/pics/action/hi16-action-rotate_right.png new file mode 100644 index 0000000..7a9119d Binary files /dev/null and b/src/pics/action/hi16-action-rotate_right.png differ diff --git a/src/pics/action/hi16-action-slideshow_pause.png b/src/pics/action/hi16-action-slideshow_pause.png new file mode 100644 index 0000000..fb08349 Binary files /dev/null and b/src/pics/action/hi16-action-slideshow_pause.png differ diff --git a/src/pics/action/hi16-action-slideshow_play.png b/src/pics/action/hi16-action-slideshow_play.png new file mode 100644 index 0000000..30c4612 Binary files /dev/null and b/src/pics/action/hi16-action-slideshow_play.png differ diff --git a/src/pics/action/hi22-action-flip.png b/src/pics/action/hi22-action-flip.png new file mode 100644 index 0000000..b5ddd6d Binary files /dev/null and b/src/pics/action/hi22-action-flip.png differ diff --git a/src/pics/action/hi22-action-mirror.png b/src/pics/action/hi22-action-mirror.png new file mode 100644 index 0000000..01e9e72 Binary files /dev/null and b/src/pics/action/hi22-action-mirror.png differ diff --git a/src/pics/action/hi22-action-rotate_left.png b/src/pics/action/hi22-action-rotate_left.png new file mode 100644 index 0000000..a3356f2 Binary files /dev/null and b/src/pics/action/hi22-action-rotate_left.png differ diff --git a/src/pics/action/hi22-action-rotate_right.png b/src/pics/action/hi22-action-rotate_right.png new file mode 100644 index 0000000..be32aab Binary files /dev/null and b/src/pics/action/hi22-action-rotate_right.png differ diff --git a/src/pics/action/hi22-action-slideshow_pause.png b/src/pics/action/hi22-action-slideshow_pause.png new file mode 100644 index 0000000..18e02ee Binary files /dev/null and b/src/pics/action/hi22-action-slideshow_pause.png differ diff --git a/src/pics/action/hi22-action-slideshow_play.png b/src/pics/action/hi22-action-slideshow_play.png new file mode 100644 index 0000000..834e364 Binary files /dev/null and b/src/pics/action/hi22-action-slideshow_play.png differ diff --git a/src/pics/action/hi32-action-flip.png b/src/pics/action/hi32-action-flip.png new file mode 100644 index 0000000..e0dd902 Binary files /dev/null and b/src/pics/action/hi32-action-flip.png differ diff --git a/src/pics/action/hi32-action-mirror.png b/src/pics/action/hi32-action-mirror.png new file mode 100644 index 0000000..a74d98d Binary files /dev/null and b/src/pics/action/hi32-action-mirror.png differ diff --git a/src/pics/action/hi32-action-rotate_left.png b/src/pics/action/hi32-action-rotate_left.png new file mode 100644 index 0000000..2c34e81 Binary files /dev/null and b/src/pics/action/hi32-action-rotate_left.png differ diff --git a/src/pics/action/hi32-action-rotate_right.png b/src/pics/action/hi32-action-rotate_right.png new file mode 100644 index 0000000..86a8085 Binary files /dev/null and b/src/pics/action/hi32-action-rotate_right.png differ diff --git a/src/pics/action/hi32-action-slideshow_pause.png b/src/pics/action/hi32-action-slideshow_pause.png new file mode 100644 index 0000000..b2d8bb7 Binary files /dev/null and b/src/pics/action/hi32-action-slideshow_pause.png differ diff --git a/src/pics/action/hi32-action-slideshow_play.png b/src/pics/action/hi32-action-slideshow_play.png new file mode 100644 index 0000000..eb24b8d Binary files /dev/null and b/src/pics/action/hi32-action-slideshow_play.png differ diff --git a/src/pics/action/hi48-action-flip.png b/src/pics/action/hi48-action-flip.png new file mode 100644 index 0000000..48b5592 Binary files /dev/null and b/src/pics/action/hi48-action-flip.png differ diff --git a/src/pics/action/hi48-action-mirror.png b/src/pics/action/hi48-action-mirror.png new file mode 100644 index 0000000..c7f92e4 Binary files /dev/null and b/src/pics/action/hi48-action-mirror.png differ diff --git a/src/pics/action/hi48-action-rotate_left.png b/src/pics/action/hi48-action-rotate_left.png new file mode 100644 index 0000000..6dfcae6 Binary files /dev/null and b/src/pics/action/hi48-action-rotate_left.png differ diff --git a/src/pics/action/hi48-action-rotate_right.png b/src/pics/action/hi48-action-rotate_right.png new file mode 100644 index 0000000..55def95 Binary files /dev/null and b/src/pics/action/hi48-action-rotate_right.png differ diff --git a/src/pics/action/hi48-action-slideshow_pause.png b/src/pics/action/hi48-action-slideshow_pause.png new file mode 100644 index 0000000..c7b1f93 Binary files /dev/null and b/src/pics/action/hi48-action-slideshow_pause.png differ diff --git a/src/pics/action/hi48-action-slideshow_play.png b/src/pics/action/hi48-action-slideshow_play.png new file mode 100644 index 0000000..d0d52b3 Binary files /dev/null and b/src/pics/action/hi48-action-slideshow_play.png differ diff --git a/src/pics/action/hisc-action-slideshow_pause.svgz b/src/pics/action/hisc-action-slideshow_pause.svgz new file mode 100644 index 0000000..2282ee4 Binary files /dev/null and b/src/pics/action/hisc-action-slideshow_pause.svgz differ diff --git a/src/pics/action/hisc-action-slideshow_play.svgz b/src/pics/action/hisc-action-slideshow_play.svgz new file mode 100644 index 0000000..d1c861e Binary files /dev/null and b/src/pics/action/hisc-action-slideshow_play.svgz differ diff --git a/src/pics/action/imageops.svg b/src/pics/action/imageops.svg new file mode 100644 index 0000000..191ef16 --- /dev/null +++ b/src/pics/action/imageops.svg @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/pics/action/imageops.svgz b/src/pics/action/imageops.svgz new file mode 100644 index 0000000..b82dbe4 Binary files /dev/null and b/src/pics/action/imageops.svgz differ diff --git a/src/pics/app/Makefile.am b/src/pics/app/Makefile.am new file mode 100644 index 0000000..a4b97f0 --- /dev/null +++ b/src/pics/app/Makefile.am @@ -0,0 +1 @@ +KDE_ICON=AUTO diff --git a/src/pics/app/hi128-app-gwenview.png b/src/pics/app/hi128-app-gwenview.png new file mode 100644 index 0000000..277769a Binary files /dev/null and b/src/pics/app/hi128-app-gwenview.png differ diff --git a/src/pics/app/hi16-app-gwenview.png b/src/pics/app/hi16-app-gwenview.png new file mode 100644 index 0000000..d93a242 Binary files /dev/null and b/src/pics/app/hi16-app-gwenview.png differ diff --git a/src/pics/app/hi22-app-gwenview.png b/src/pics/app/hi22-app-gwenview.png new file mode 100644 index 0000000..1f98c35 Binary files /dev/null and b/src/pics/app/hi22-app-gwenview.png differ diff --git a/src/pics/app/hi32-app-gwenview.png b/src/pics/app/hi32-app-gwenview.png new file mode 100644 index 0000000..5421fd8 Binary files /dev/null and b/src/pics/app/hi32-app-gwenview.png differ diff --git a/src/pics/app/hi48-app-gwenview.png b/src/pics/app/hi48-app-gwenview.png new file mode 100644 index 0000000..5db2a9a Binary files /dev/null and b/src/pics/app/hi48-app-gwenview.png differ diff --git a/src/pics/app/hi64-app-gwenview.png b/src/pics/app/hi64-app-gwenview.png new file mode 100644 index 0000000..c427605 Binary files /dev/null and b/src/pics/app/hi64-app-gwenview.png differ diff --git a/src/pics/app/hisc-app-gwenview.svgz b/src/pics/app/hisc-app-gwenview.svgz new file mode 100644 index 0000000..70ad5a1 Binary files /dev/null and b/src/pics/app/hisc-app-gwenview.svgz differ diff --git a/src/pics/cursor/Makefile.am b/src/pics/cursor/Makefile.am new file mode 100644 index 0000000..3143a4e --- /dev/null +++ b/src/pics/cursor/Makefile.am @@ -0,0 +1,2 @@ +cursorsdir=$(kde_datadir)/gwenview/cursors +cursors_DATA=zoom.png diff --git a/src/pics/cursor/zoom.png b/src/pics/cursor/zoom.png new file mode 100644 index 0000000..2250544 Binary files /dev/null and b/src/pics/cursor/zoom.png differ diff --git a/src/pics/thumbnail/Makefile.am b/src/pics/thumbnail/Makefile.am new file mode 100644 index 0000000..767c22b --- /dev/null +++ b/src/pics/thumbnail/Makefile.am @@ -0,0 +1,2 @@ +thumbnaildir=$(kde_datadir)/gwenview/thumbnail +thumbnail_DATA=wait.png diff --git a/src/pics/thumbnail/wait.png b/src/pics/thumbnail/wait.png new file mode 100644 index 0000000..62008cd Binary files /dev/null and b/src/pics/thumbnail/wait.png differ diff --git a/src/spec/gwenview-RH.spec b/src/spec/gwenview-RH.spec new file mode 100644 index 0000000..1b664db --- /dev/null +++ b/src/spec/gwenview-RH.spec @@ -0,0 +1,86 @@ +%define desktop_vendor rockers + +Name: gwenview +Summary: Gwenview is an image viewer for KDE. +Version: 0.16.2 +Release: 0 +License: GPL +Group: Amusements/Graphics +Source: http://prdownloads.sourceforge.net/gwenview/%{name}-%{version}.tar.bz2 +BuildRoot: %{_tmppath}/%{name}-root +Url: http://gwenview.sourceforge.net/home/ +Requires: libpng, kdebase >= 3.0 +BuildRequires: libpng-devel, kdelibs-devel, arts-devel, libjpeg-devel +BuildRequires: XFree86-devel, zlib-devel, qt-devel >= 3.0.2 + +%description +Gwenview is an image viewer for KDE. + +It features a folder tree window and a file list window to +provide easy navigation among your thousand images. + +Image loading is done by the Qt library, giving you access +to all image formats your Qt installation supports, but +Gwenview can also browse GIMP files (*.xcf) thanks to the +included QXCFI component developed by Lignum Computing. + +Gwenview correctly displays images with alpha channel, +using the traditionnal checker board as a background to +reveal transparency. + +%prep +rm -rf %{buildroot} + +%setup -q + +%build +%configure --with-xinerama +make %{_smp_mflags} + +%install +%makeinstall + +desktop-file-install --vendor %{desktop_vendor} --delete-original \ + --dir %{buildroot}%{_datadir}/applications \ + --add-category X-Red-Hat-Extra \ + --add-category Application \ + --add-category Graphics \ + %{buildroot}%{_datadir}/applnk/Graphics/%{name}.desktop + +rm -rf %{buildroot}%{_datadir}/applnk + +mv %{buildroot}%{_datadir}/hicolor/16x16/actions/ \ +%{buildroot}%{_datadir}/icons/hicolor/16x16 + +mkdir %{buildroot}%{_datadir}/icons/hicolor/22x22 +mv %{buildroot}%{_datadir}/hicolor/22x22/actions/ \ +%{buildroot}%{_datadir}/icons/hicolor/22x22 + +mv %{buildroot}%{_datadir}/hicolor/32x32/actions/ \ +%{buildroot}%{_datadir}/icons/hicolor/32x32 + +rm -rf %{buildroot}%{_datadir}/hicolor + +%clean +rm -rf %{buildroot} + +%post + +%postun + +%files +%defattr(-,root,root,-) +%doc AUTHORS COPYING README INSTALL CREDITS TODO NEWS +%{_bindir}/%{name}* +%{_mandir}/man1/%{name}* +%{_datadir}/apps/konqueror/servicemenus/konqgwenview.desktop +%{_datadir}/applications/%{desktop_vendor}-%{name}.desktop +%{_datadir}/icons/*/*/*/* +%{_datadir}/locale/*/LC_MESSAGES/%{name}* + +%changelog +* Fri Feb 14 2003 Robert Rockers 0.16.2 +- Recompiled for version 0.16.2 + +* Fri Feb 7 2003 Robert Rockers 0.16.1 +- Initial RedHat RPM release. diff --git a/src/spec/gwenview-SuSE.spec b/src/spec/gwenview-SuSE.spec new file mode 100644 index 0000000..2d90254 --- /dev/null +++ b/src/spec/gwenview-SuSE.spec @@ -0,0 +1,45 @@ +Summary:Simple image viewer for KDE +Name: gwenview +Version: 0.15.1 +Release: 1 +Copyright: GPL +Group: Application/Multimedia +Source0: %{name}-%{version}.tar.bz2 +URL: http://gwenview.sourceforge.net + +Packager: Dario Abatianni + +BuildRoot: /tmp/build/%{name}-%{version} + +%description +Gwenview is an image viewer for KDE 3.x. + +It features a folder tree window and a file list window to provide easy +navigation in your file hierarchy. Image loading is done by the Qt library, +so it supports all image formats your Qt installation supports. + +%prep +rm -rf $RPM_BUILD_ROOT + +%setup + +%build +./configure --prefix=$RPM_BUILD_ROOT/opt/kde3 --enable-final +make + +%install +make install + +%files +%defattr(-,root,root,0755) +/opt/kde3/bin/gwenview +/opt/kde3/share/apps/gwenview/icons/*/*/actions/*.png +/opt/kde3/share/icons/*/*/apps/gwenview.png +/opt/kde3/share/applnk/Graphics/gwenview.desktop +/opt/kde3/share/apps/konqueror/servicemenus/konqgwenview.desktop +/opt/kde3/share/locale/*/LC_MESSAGES/gwenview.mo +/opt/kde3/man/man1/gwenview.1 +%doc NEWS README TODO ChangeLog COPYING CREDITS + +%clean +rm -rf $RPM_BUILD_ROOT diff --git a/src/spec/gwenview-mdk.spec b/src/spec/gwenview-mdk.spec new file mode 100644 index 0000000..a78f9c2 --- /dev/null +++ b/src/spec/gwenview-mdk.spec @@ -0,0 +1,466 @@ +%define gvname gwenview +%define version 1.2.92 +## Distribution Specific Release Tag +%{?!mkrel: %define mkrel(c:) %{-c:0.%{-c*}.}%{!?_with_unstable:%(perl -e '$_="%{1}";m/(.\*)(\\d+)$/;$rel=${2}-1;re;print "$1$rel";').%{?subrel:%subrel}%{!?subrel:1}.%{?distversion:%distversion}%{?!distversion:%(echo $[%{mdkversion}/10])}}%{?_with_unstable:%{1}}%{?distsuffix:%distsuffix}%{?!distsuffix:mdk}} +%define release %mkrel 1 + +%define gvcorename libgwenviewcore +%define gvdirpartname gvdirpart +%define gvimagepartname gvimagepart + +%define name %gvname + +%define major 1 +%define libname %mklibname %{gvname} %major +%define libnamedev %mklibname %{gvname} %major -d + +# building kipi version +%define build_kipi 1 +%{?_with_nokipi: %global build_kipi 0} +%if %build_kipi +%define kipiopt --enable-kipi +%define kipireq libkipi-devel +%endif + + +Summary: Fast and easy to use image viewer for KDE +Name: %name +Version: %version +Release: %release +License: GPL +Group: Graphics +Source0: http://prdownloads.sourceforge.net/gwenview/%{gvname}-%{version}.tar.bz2 + +URL: http://gwenview.sourceforge.net +BuildRoot: %_tmppath/%{name}-%{version} +# added automake1.7 requirement to patch Makefile(s).am +%if %build_kipi +BuildRequires: kdelibs-devel automake1.7 X11-devel %{kipireq} +%else +BuildRequires: kdelibs-devel automake1.7 X11-devel +%endif + + +%description +Gwenview is a fast and easy to use image viewer/browser for KDE. +All common image formats are supported, such as PNG(including transparency), +JPEG(including EXIF tags and lossless transformations), GIF, XCF (Gimp +image format), BMP, XPM and others. Standard features include slideshow, +fullscreen view, image thumbnails, drag'n'drop, image zoom, full network +transparency using the KIO framework, including basic file operations and +browsing in compressed archives, non-blocking GUI with adjustable views. +Gwenview also provides image and directory KParts components for use e.g. in +Konqueror. Additional features, such as image renaming, comparing, +converting, and batch processing, HTML gallery and others are provided by the +KIPI image framework. + +%package -n %libname +Summary: Libraries for gwenview image viewer +Group: System/Libraries +Requires: %{name} = %{version} + +%description -n %libname +Gwenview is a fast and easy to use image viewer/browser for KDE. +%{libname} contains the libraries needed to use %{gvname} + +%package -n %libnamedev +Summary: Devel files (gwenview image viewer) +Group: Development/Other +Requires: %libname = %{version} +Provides: lib%{gvname}-devel = %{version}-%{release} +Provides: %{gvname}-devel = %{version}-%{release} + +%description -n %libnamedev +Gwenview is a fast and easy to use image viewer/browser for KDE. +%{libnamedev} contains the libraries and header files needed to +develop programs which make use of %{libname}. + +%prep +rm -rf $RPM_BUILD_ROOT + +%setup -q -n %{gvname}-%{version} + +%build +make -f admin/Makefile.common cvs + +export QTDIR=%_prefix/%_lib/qt3 +export KDEDIR=%_prefix + +export LD_LIBRARY_PATH=$QTDIR/%_lib:$KDEDIR/%_lib:$LD_LIBRARY_PATH +export PATH=$QTDIR/bin:$KDEDIR/bin:$PATH + +# Search for qt/kde libraries in the right directories (avoid patch) +# NOTE: please don't regenerate configure scripts below +perl -pi -e "s@/lib(\"|\b[^/])@/%_lib\1@g if /(kde|qt)_(libdirs|libraries)=/" configure + +./configure --disable-rpath \ +%if %build_kipi + %kipiopt \ +%else + \ +%endif + --prefix=%_prefix \ + --libdir=%_libdir \ + --mandir=%_mandir \ + --datadir=%_datadir + + +%make + +%install +rm -rf $RPM_BUILD_ROOT +mkdir -p %buildroot/%_datadir/applnk/Multimedia/Graphics +%makeinstall + +install -d %buildroot/%_menudir/ +kdedesktop2mdkmenu.pl %{gvname} "Multimedia/Graphics" %buildroot/%_datadir/applications/kde/%{gvname}.desktop %buildroot/%_menudir/%{gvname} + +#icons for rpmlint +mkdir -p %buildroot/{%_liconsdir,%_miconsdir,%_iconsdir} +ln -s %_datadir/icons/hicolor/64x64/apps/%{gvname}.png %buildroot/%_liconsdir +ln -s %_datadir/icons/hicolor/32x32/apps/%{gvname}.png %buildroot/%_iconsdir +ln -s %_datadir/icons/hicolor/16x16/apps/%{gvname}.png %buildroot/%_miconsdir + +%find_lang %{gvname} + +%post +%update_menus + +%postun +%clean_menus + +%post -n %libname -p /sbin/ldconfig + +%postun -n %libname -p /sbin/ldconfig + +%files -f %{gvname}.lang +%defattr(-,root,root,0755) +%doc NEWS AUTHORS README TODO ChangeLog COPYING INSTALL +%_bindir/%{gvname} + +%dir %_datadir/apps/%{gvdirpartname}/ +%_datadir/apps/%{gvdirpartname}/gvdirpart.rc + +%dir %_datadir/apps/%{gvimagepartname}/ +%_datadir/apps/%{gvimagepartname}/gvimagepart.rc +%_datadir/services/%{gvdirpartname}.desktop +%_datadir/services/%{gvimagepartname}.desktop +%_menudir/* +%_datadir/apps/konqueror/servicemenus/* +%_datadir/apps/kconf_update/%{gvname}* +%dir %_datadir/apps/%{gvname}/ +%_datadir/apps/%{gvname}/* +%_datadir/icons/crystalsvg/16x16/apps/* +%_datadir/icons/crystalsvg/22x22/apps/* +%_datadir/icons/hicolor/* +%_liconsdir/%{gvname}.png +%_iconsdir/%{gvname}.png +%_miconsdir/%{gvname}.png +%_datadir/applications/kde/%{gvname}.desktop +%_datadir/config.kcfg/gvconfig.kcfg +%dir %_datadir/doc/HTML/ +%_datadir/doc/HTML/* +%_mandir/man1/%{gvname}.1.bz2 + +%_libdir/kde3/* +%_libdir/libkdeinit_%{gvname}.so +%_libdir/libkdeinit_%{gvname}.la + +%files -n %libname +%defattr(-,root,root,0755) +%_libdir/*.so.* + +%files -n %libnamedev +%defattr(-,root,root,0755) +%_includedir/libgwenview_export.h +%_libdir/%{gvcorename}.so +%_libdir/%{gvcorename}.la + +%clean +rm -rf $RPM_BUILD_ROOT + +%changelog +* Sun Aug 21 2005 Angelo Naselli 1.2.92-1mdk +- New release 1.2.92 + +* Wed Jul 20 2005 Angelo Naselli 1.2.91-1mdk +- New release 1.2.91 +- patched for fvisibility problem (aligned to svn) + +* Mon May 09 2005 Laurent MONTEL 1.2.0-4 +- Real fix build on x86_64 + +* Sun May 08 2005 Angelo Naselli 1.2.0-3mdk +- fix for x86_64 arch + +* Sun May 08 2005 Angelo Naselli 1.2.0-2mdk +- Rebuild + +* Sun Apr 03 2005 Angelo Naselli 1.2.0-1mdk +- really built new version + +* Sun Mar 20 2005 Angelo Naselli 1.2.0-0.pre4.2mdk +- really built new version + +* Sun Mar 20 2005 Angelo Naselli 1.2.0-0.pre4.1mdk +- new version + +* Sat Mar 19 2005 Angelo Naselli 1.2.0-0.pre3.2mdk +- fix bug #14731 + +* Sun Feb 27 2005 Angelo Naselli 1.2.0-0.pre3.1mdk +- new version + +* Sun Feb 13 2005 Angelo Naselli 1.2.0-0.pre2.2mdk +- define mkrel macro if not exist + +* Sun Feb 13 2005 Angelo Naselli 1.2.0-0.pre2.1mdk +- new version + +* Sat Jan 29 2005 Angelo Naselli 1.2.0-0.pre1.2mdk +- added patch to make it compile for mdk official 10.1 +- added patch to fix zoom (from cvs) +- added patch to add missing files (from cvs) + +* Mon Jan 24 2005 Angelo Naselli 1.2.0-0.pre1.1mdk +- new version + +* Wed Jan 19 2005 Angelo Naselli 1.1.8-0.4mdk +- fix bug 13100 + +* Sun Jan 16 2005 Angelo Naselli 1.1.8-0.3mdk +- better handling of symlink + +* Thu Jan 13 2005 Angelo Naselli 1.1.8-0.2mdk +- fix double click into kpart + +* Sun Jan 09 2005 Angelo Naselli 1.1.8-0.1mdk +- 1.1.8 +- fix Requires section to be compliant to the library policy + +* Thu Dec 30 2004 Angelo Naselli 1.1.7-0.5mdk +- added 1.1.7b patch (solved some build problems) + +* Wed Dec 29 2004 Angelo Naselli 1.1.7-0.4mdk +- description restyling + +* Sun Dec 26 2004 Angelo Naselli 1.1.7-0.3mdk +- fix Require and Provide section + +* Sun Dec 26 2004 Angelo Naselli 1.1.7-0.2mdk +- removed hack management +- added distro-specific release tag management + use option "--with official" to build mdk official package + +* Mon Dec 20 2004 Laurent MONTEL 1.1.7-0.1mdk +- 1.1.7 + +* Fri Dec 10 2004 Laurent MONTEL 1.1.6-0.2mdk +- Fix spec file + +* Sun Oct 24 2004 Angelo Naselli 1.1.6-0.1mdk +- new version + * New features: + o The application now has two modes: browse and view. Browse mode shows + all views: folder, file and image. View mode only shows the image. + Gwenview starts in browse mode except if an image URL is given as + an argument. You can switch between modes using the toolbar button, + or with the "View/Browse mode" menu item or with the Ctrl+Return shortcut. + o JPEGTran code has been integrated into Gwenview, there's no need to install + it separately anymore. + * Fixes: + o Update the EXIF thumbnail when rotating a JPEG file. + o In the folder view, folders now open with a single click (By Daniel Thaler). + o Reworked coordinate conversions in order to avoid subtle paint errors. + o Remember computed optimal repaint sizes in the config file, + so they are available immediately after next start. + o Remember shown URL after session restore. +* Sat Oct 16 2004 Angelo Naselli 1.1.5-0.3mdk +- rebuilt for new liblipi + fixing +* Sat Oct 09 2004 Angelo Naselli 1.1.5-0.2mdk +- applied Lubos Lunak's patch to avoid printing crash using Konqueror +* Mon Sep 20 2004 Angelo Naselli 1.1.5-0.1mdk +- new version + * New features: + o The thumbnail progress bar and stop buttons are now embedded in the thumbnail view. + o The location bar now shows the file names instead of the folders. + o The thumbnails toolbar buttons have been moved to a specialized file view toolbar. + o It's now possible to assign key shortcuts to KIPI plugins. + o New manpage by Christopher Martin. + * Fixes: + o Do not display the folder name as an image in the status bar. + o Make sure the folder KPart starts in the right folder. + o Unbreak the saving of key shortcuts. + o Remote urls are correctly bookmarked. + o Do not try to overwrite the trash when trashing only one file. + +* Sun Aug 29 2004 Angelo Naselli 1.1.4-0.2mdk +- patch for russian language + +* Tue Aug 24 2004 Angelo Naselli 1.1.4-0.1mdk +- changed spec file to manage -with-hack option to build gwenview with + hack suffix (default is without hack) +- from Aurlien Gteau: +- New features: + - In the thumbnail view, It's now possible to sort images in reverse order. + - Use EXIF-stored thumbnail if available. + - Option to disable saving of generated thumbnails to cache. + - In fullscreen mode, it's now possible to display the image comment or size + in addition to the file path. + - The fullscreen On-Screen-Display is more readable now. + - The background color of the image view can be configured. + - When printing, it's now possible to enlarge images so that they fill the + page. +- Fixes: + - In the folder view, pressing Enter now opens the selected folder. + - Use icon list for the configuration dialog. + - Avoid data loss if the JPEG images are saved while being rotated by + JPEGTran. + - The back button in Konqueror now works correctly with gvimagepart. + - The default layout is more user-friendly. + - Non-trivial URLs (e.g. http query URL) are correctly handled. + - You can now drop images on the image view. + +* Sat Jun 12 2004 Angelo Naselli 1.1.3-0.1mdk +- new release: my wedding present :-) + from Aurlien Gteau: + Gwenview codenamed "Hurry up, I'm getting married tomorrow" + * New features: + o You can now define custom branches in the dir view (By Craig Drummond) + o An image cache has been added to speedup image loading. + o Gwenview now uses freedesktop.org thumbnail spec to store thumbnails. + o A new option to automatically empty thumbnail cache on exit (By Angelo Naselli). + o The image size is now displayed below file names in thumbnail view. + * Fixes: + o Don't crash when switching to fullscreen while generating thumbnails and coming back (By Lubos Lunak) + o Faster thumbnail generation (By Lubos Lunak) + o Faster image painting by dynamically determining suitable paint size (By Lubos Lunak) + o Use the "Standard Background" color as the background for thumbnails and folders (By Craig Drummond). + o Make sure the current image is reloaded if it has been modified outside Gwenview. + +* Tue Jun 1 2004 Angelo Naselli 1.1.2-0.3mdk +- hack suffix on kpart lib + +* Thu May 13 2004 Lenny Cartier 1.1.2-0.2mdk +- merge with changes from Angelo Naselli + +* Wed May 12 2004 Lenny Cartier 1.1.2-0.1mdk +- 1.1.2 +- from Angelo Naselli : +- mdk version of the development release (1.1.1) named gwenview_hack + from Aurlien Gteau: + - New features: + - Added KPart support, this installs in Konqueror a new file view mode and let you view + images in an embedded Gwenview (By Jonathan Riddell). + - Asynchronous JPEG loading, based on Khtml loader. + - Really asynchronous PNG loading (By Lubos Lunak). + - Mouse wheel will now scroll the image by default. Holding Ctrl will scroll horizontally. + An option has been added to the setting dialog to toggle between scroll and browse + (By Jeroen Peters). + - When holding shift over the image, right click will zoom out (By Jeroen Peters). + - Image painting is now progressive (By Lubos Lunak). + - Fixes: + - The rotate and mirror functions can now work on multiple selection. + - Make it possible to load another image or quit even if you can't save your changes. + - Gwenview won't spawn multiple instances of jpegtran anymore. + +* Sun Feb 01 2004 Angelo Naselli 1.1.0-0.1mdk +- mdk version of the first development release (1.1.0) + from Aurlien Gteau: + - New features: + - New settings in print dialog to specify how the image must be printed. + - Big thumbnails are really BIG now. + - First implementation of asynchronous image loading. Only for PNG right now. + - Fixes: + - The move and copy dialogs now use a tree view. + - In the thumbnail view, create thumbnails for the visible images first + +* Sun Jan 11 2004 Angelo Naselli 1.0.1-0.1mdk +- built mdk version of Gwenview 1.0.0 release +- fix icons for rpmlint + from Aurlien Gteau: + - New features: + - Double-clicking an image in the file view will open it in fullscreen. + - Fixes: + - Gave contributors the credit they deserve in the about box. + - Updated to libexif 0.5.12 and applied patch from libexif CVS. + - When going to the parent folder, make sure the folder we were in before is selected. + - If there's no image in the current folder, select the first visible file. + - When holding down Shift to zoom, keep the same area of the image under the cursor. + - Nicer drag cursor. + - Hopefully fixed every cases where the image was not centered in the view. + +* Mon Dec 08 2003 Angelo Naselli 1.0.0-0.1mdk +- built mdk version of Gwenview 1.0.0 release + from Aurlien Gteau: + - New features: + - Show a wait icon for not-generated-yet thumbnails (inspired from Nautilus + thumbnail view). + - Show a broken icon for broken images. + - Fixes: + - If auto-zoom is on, make sure the zoom is updated after rotating an image. + - Fixed crash when loading XCF images if Gwenview was compiled with gcc 3.3.1. + - Before running an external tool, change working directory to current folder. + - When switching images in fullscreen, don't show the cursor. + - Use standard KDE icons for zoom actions. + - New icons for slideshow and image operations. + - New magnifier cursor. + +* Sun Nov 16 2003 Angelo Naselli 1.0.0-0.pre4.1mdk +- built mdk version + from Aurlien Gteau: + - New features + - Added a new option to hide the busy pointer when loading an + image in fullscreen. + - Added a popup menu to select the sorting mode. + Usefull in thumbnail view. + - Fixes: + - Use a KDE dialog for the configuration dialog. + - Removed the image view mouse behavior configuration + options. The behavior is much simpler now: left button + to drag image, + - middle button to toggle auto-zoom and mouse-wheel + to browse images. Ifrom Aurlien Gteauef you want to zoom hold Shift + and use either the mouse-wheel or the left button. + +* Wed Nov 05 2003 Marcel Pol 1.0.0-0.pre3.2mdk +- redo changelog +- rm -rf $RPM_BUILD_ROOT in %%install instead of %%prep + +* Tue Nov 04 2003 Angelo Naselli 1.0.0-0.pre3.1mdk +- built mdk version + - New features from Aurlien Gteau: + - Added a "don't ask me again" check box to the save prompt dialog. + - Added a reload button. + - Added a "Go" button to the location toolbar. + - Fixes: + - Really fixed saving of external tools. + - Make sure the folder view is updated when a folder is renamed. + - The mouse-wheel behaviors are not messed anymore by dialogs or by + showing the popup menu. + +* Mon Nov 03 2003 Marcel Pol 1.0.0-0.pre2.2mdk +- buildrequires +- quiet setup + +* Wed Oct 22 2003 Angelo Naselli 1.0.0-0.pre2.1mdk +- added some changes on spec file imported from + Lenny Cartier 1.0.0-0.pre1.1mdk + +* Mon Oct 20 2003 Lenny Cartier 1.0.0-0.pre1.1mdk +- from Angelo Naselli : + - built mdk version + +* Mon Oct 12 2003 Angelo Naselli 1.0.0pre2-1mdk +- fixed some bugs on spec file +- built mdk version + +* Mon Oct 6 2003 Angelo Naselli 1.0.0pre1-2mdk +- Added print button patch + +* Mon Sep 29 2003 Angelo Naselli 1.0.0pre1-1mdk +- built mdk version + +* Fri Aug 08 2003 Angelo N. 0.17.1a-1mdk +- built mdk version + diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am new file mode 100644 index 0000000..b689d90 --- /dev/null +++ b/src/tools/Makefile.am @@ -0,0 +1,3 @@ +toolsdir=$(kde_datadir)/gwenview/tools +tools_DATA=gimp.desktop wallpaper.desktop tiledwallpaper.desktop \ + konqueror.desktop kolourpaint.desktop diff --git a/src/tools/gimp.desktop b/src/tools/gimp.desktop new file mode 100644 index 0000000..8882956 --- /dev/null +++ b/src/tools/gimp.desktop @@ -0,0 +1,37 @@ +[Desktop Entry] +ServiceTypes=image/* +Exec=gimp-remote %F +Icon=gimp +Name=The GIMP +Name[br]=Ar GIMP +Name[bs]=GIMP +Name[ca]=El GIMP +Name[da]=GIMP +Name[de]=GIMP +Name[el]=Το GIMP +Name[et]=GIMP +Name[fa]=GIMP +Name[fi]=GIMP +Name[fr]=GIMP +Name[gl]=O Gimp +Name[hi]=द गिम्प +Name[hr]=GIMP +Name[hu]=A GIMP +Name[it]=GIMP +Name[ms]=GIMP +Name[nds]=GIMP +Name[pa]=ਜੈਮਪ +Name[pl]=GIMP +Name[pt]=O GIMP +Name[pt_BR]=O GIMP +Name[ru]=GIMP +Name[sk]=GIMP +Name[sl]=GIMP +Name[sr]=GIMP +Name[sr@Latn]=GIMP +Name[sv]=GIMP +Name[tg]=ГИМП +Name[tr]=GIMP +Name[uk]=GIMP +Name[vi]=GIMP +Name[xx]=xxThe GIMPxx diff --git a/src/tools/kolourpaint.desktop b/src/tools/kolourpaint.desktop new file mode 100644 index 0000000..2cce8ee --- /dev/null +++ b/src/tools/kolourpaint.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +ServiceTypes=image/* +Name=KolourPaint +Name[pa]=ਕੇ-ਰੰਗ-ਪੇਂਟ +Name[xx]=xxKolourPaintxx +Icon=kolourpaint +Exec=kolourpaint %u diff --git a/src/tools/konqueror.desktop b/src/tools/konqueror.desktop new file mode 100644 index 0000000..b307f9a --- /dev/null +++ b/src/tools/konqueror.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +ServiceTypes=* +Exec=konqueror %u +Icon=konqueror +Name=Konqueror +Name[hi]=कॉन्क्वेरर +Name[pa]=ਕੋਨਕਿਊਰੋਰ +Name[ta]=கான்குவரர் +Name[tg]=Конкуерор +Name[xx]=xxKonquerorxx diff --git a/src/tools/tiledwallpaper.desktop b/src/tools/tiledwallpaper.desktop new file mode 100644 index 0000000..3c91c47 --- /dev/null +++ b/src/tools/tiledwallpaper.desktop @@ -0,0 +1,43 @@ +[Desktop Entry] +ServiceTypes=image/* +Exec=dcop kdesktop KBackgroundIface setWallpaper %u 2 +Icon=background +Name=Set as Tiled Wallpaper +Name[bg]=Използване като тапет със застилане +Name[ca]=Estableix com a paper pintat (mosaic) +Name[cs]=Použít jako dlaždice na plochu +Name[da]=Sæt som fliselagt tapet +Name[de]=Als Hintergrundbild verwenden (gekachelt) +Name[el]=Ορισμός σαν Ταπετσαρία σε παράθεση +Name[es]=Establecer como fondo de pantalla embaldosado +Name[et]=Sea paanidena taustapildiks +Name[fa]=تنظیم به عنوان کاغذدیواری کاشی‌شده +Name[fi]=Aseta taustakuvaksi monistettuna +Name[fr]=Établir comme papier peint en mosaïque +Name[gl]=Colocar como Fondo de Escritório en Mosaico +Name[hi]=टाइल्ड वालपेपर के रूप में सेट करें +Name[hr]=Popločeno na radnu površinu +Name[hu]=Beállítás háttérképnek (mozaikszerűen) +Name[is]=Setja sem flísalagt veggfóður +Name[it]=Imposta come immagine di sfondo ripetuta +Name[ja]=タイルされた壁紙として設定 +Name[ka]=მოზაიკურ ფონად დაყენება +Name[ms]=Tetapn sebagai Kertas Dinding Jubin +Name[nds]=As kachelt Achtergrundbild fastleggen +Name[nl]=Als getegelde achtergrondafbeelding instellen +Name[pa]=ਤਣਿਆ ਵਾਲਪੇਪਰ ਬਣਾਓ +Name[pl]=Ustaw jako kafelkowaną tapetę +Name[pt]=Colocar como Fundo de Ecrã em Mosaico +Name[pt_BR]=Configurar como papel de parede ladrilhado +Name[ru]=Расположить черепицей на рабочем столе +Name[sk]=Nastaviť ako pozadie (dlaždice) +Name[sr]=Постави као поплочану позадину +Name[sr@Latn]=Postavi kao popločanu pozadinu +Name[sv]=Ange som skrivbordsunderlägg sida vid sida +Name[ta]=முழுவதும் வால்பேப்பராக அமை +Name[tg]=Сурати мизи кориро бо мавзӯъи сафолӣ танзим кунед +Name[tr]=Döşenmiş Duvar Kağıdı Yap +Name[uk]=Встановити як шпалери (плиткою) +Name[vi]=Đặt là ảnh nền màn hình đã lát đều +Name[xx]=xxSet as Tiled Wallpaperxx +Name[zh_CN]=设为平铺墙纸 diff --git a/src/tools/wallpaper.desktop b/src/tools/wallpaper.desktop new file mode 100644 index 0000000..5287a5b --- /dev/null +++ b/src/tools/wallpaper.desktop @@ -0,0 +1,45 @@ +[Desktop Entry] +ServiceTypes=image/* +Exec=dcop kdesktop KBackgroundIface setWallpaper %u 6 +Icon=background +Name=Set as Wallpaper +Name[ar]=عيين كورق جدار +Name[bg]=Използване като тапет +Name[ca]=Estableix com a paper pintat +Name[cs]=Použít jako tapetu +Name[cy]=Gosod fel Papur Wal +Name[da]=Sæt som tapet +Name[de]=Als Hintergrundbild verwenden +Name[el]=Ορισμός σαν Ταπετσαρία +Name[es]=Establecer como fondo +Name[et]=Sea taustapildiks +Name[fa]=تنظیم به عنوان کاغذدیواری +Name[fi]=Aseta taustakuvaksi +Name[fr]=Établir comme papier peint +Name[gl]=Colocar como Fondo de Escritório +Name[hi]=वालपेपर के रूप में सेट करें +Name[hr]=Postavi na radnu površinu +Name[hu]=Beállítás háttérképnek +Name[is]=Setja sem veggfóður +Name[it]=Imposta come immagine di sfondo +Name[ja]=壁紙として設定 +Name[ka]=ფონად მითითება +Name[ms]=Tetapn sebagai Kertas Dinding +Name[nds]=As Achtergrundbild fastleggen +Name[nl]=Als achtergrondafbeelding instellen +Name[pa]=ਵਾਲਪੇਪਰ ਸੈੱਟ ਕਰੋ +Name[pl]=Ustaw jako tapetę +Name[pt]=Colocar como Fundo de Ecrã +Name[pt_BR]=Configurar como papel de parede +Name[ru]=Сделать рисунком рабочего стола +Name[sk]=Nastaviť ako pozadie +Name[sr]=Постави као позадину +Name[sr@Latn]=Postavi kao pozadinu +Name[sv]=Ange som skrivbordsunderlägg +Name[ta]=வால்பேப்பராக அமைக்கவும் +Name[tg]=Танзими сурати мизи корӣ +Name[tr]=Duvar Kağıdı Yap +Name[uk]=Встановити як шпалери +Name[vi]=Đặt là ảnh nền màn hình +Name[xx]=xxSet as Wallpaperxx +Name[zh_CN]=设为墙纸 diff --git a/src/tsthread/Makefile.am b/src/tsthread/Makefile.am new file mode 100644 index 0000000..cd0ed32 --- /dev/null +++ b/src/tsthread/Makefile.am @@ -0,0 +1,12 @@ +INCLUDES = -I$(srcdir) -I$(srcdir)/.. $(all_includes) + +noinst_LTLIBRARIES = libtsthread.la + +libtsthread_la_SOURCES = \ + tsthread.cpp \ + tswaitcondition.cpp + +noinst_HEADERS = \ + tsthread.h + +METASOURCES = AUTO diff --git a/src/tsthread/tsthread.cpp b/src/tsthread/tsthread.cpp new file mode 100644 index 0000000..16b4538 --- /dev/null +++ b/src/tsthread/tsthread.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** + + Copyright (C) 2004 Lubos Lunak + +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, sublicense, +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 OR COPYRIGHT HOLDERS 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 "tsthread.h" + +#include +#include +#include +#include + +#include + +#ifdef TS_QTHREADSTORAGE +QThreadStorage< TSThread** >* TSThread::current_thread; +#else +TSCurrentThread* TSThread::current_thread; +#endif +TSThread* TSThread::main_thread = NULL; + +class TSMainThread + : public TSThread + { + protected: + virtual void run() { assert( false ); } + }; + +TSThread::Helper::Helper( TSThread* parent ) + : thread( parent ) + { + assert( parent ); + } + +void TSThread::Helper::run() + { + thread->executeThread(); + } + + +TSThread::TSThread() + : thread( this ) + , cancelling( false ) + , emit_pending( false ) + , cancel_mutex( NULL ) + , cancel_cond( NULL ) + , deleted_flag( NULL ) + { + } + +TSThread::~TSThread() + { + if( deleted_flag != NULL ) + *deleted_flag = true; + } + +void TSThread::start() + { + if( current_thread == NULL ) + initCurrentThread(); + thread.start(); + } + +void TSThread::cancel() + { + QMutexLocker lock( &mutex ); + cancelling = true; + if( cancel_mutex != NULL ) + { + QMutexLocker lock( cancel_mutex ); + cancel_cond->wakeAll(); + } + } + +void TSThread::wait( unsigned long time ) + { + thread.wait( time ); + } + +bool TSThread::finished() const + { + return thread.finished(); + } + +bool TSThread::running() const + { + return thread.running(); + } + +void TSThread::initCurrentThread() + { +#ifdef TS_QTHREADSTORAGE + current_thread = new QThreadStorage< TSThread** >(); + typedef TSThread* TSThreadPtr; + // set pointer for main thread (this must be main thread) + current_thread->setLocalData( new TSThreadPtr( NULL )); // TODO NULL ? +#else + current_thread = new TSCurrentThread(); + main_thread = new TSMainThread; + // set pointer for main thread (this must be main thread) + current_thread->setLocalData( main_thread ); +#endif + } + +void TSThread::executeThread() + { +#ifdef TS_QTHREADSTORAGE + // store dynamically allocated pointer, so that + // QThreadStorage deletes the pointer and not TSThread + typedef TSThread* TSThreadPtr; + current_thread->setLocalData( new TSThreadPtr( this )); +#else + current_thread->setLocalData( this ); +#endif + run(); + postSignal( this, NULL ); // = terminated() + } + +void TSThread::postSignal( QObject* obj, const char* signal ) + { + assert( currentThread() == this ); + qApp->postEvent( this, new SignalEvent( signal, obj, NULL )); + } + +void TSThread::emitSignalInternal( QObject* obj, const char* signal, QUObject* o ) + { + assert( currentThread() == this ); + QMutexLocker locker( &signal_mutex ); + emit_pending = true; + qApp->postEvent( this, new SignalEvent( signal, obj, o )); + while( emit_pending ) + signal_cond.wait( &signal_mutex ); + } + +void TSThread::emitCancellableSignalInternal( QObject* obj, const char* signal, QUObject* o ) + { + assert( currentThread() == this ); + // can't use this->mutex, because its locking will be triggered by TSWaitCondition + QMutexLocker locker( &signal_mutex ); + emit_pending = true; + qApp->postEvent( this, new SignalEvent( signal, obj, o )); + while( emit_pending && !testCancel()) + signal_cond.cancellableWait( &signal_mutex ); + emit_pending = false; // in case of cancel + } + +void TSThread::customEvent( QCustomEvent* ev ) + { + SignalEvent* e = static_cast< SignalEvent* >( ev ); + if( e->signal.isEmpty()) // = terminated() + { // threadExecute() finishes before the actual thread terminates + if( !finished()) + wait(); + emit terminated(); + return; + } + bool deleted = false; + deleted_flag = &deleted; // this is like QGuardedPtr for self, but faster + int signal_id = e->object->metaObject()->findSignal( normalizeSignalSlot( e->signal ).data() + 1, true ); + if( signal_id >= 0 ) + e->object->qt_emit( signal_id, e->args ); + else + kdWarning() << "Cannot emit signal \"" << e->signal << "\"." << endl; + if( deleted ) // some slot deleted 'this' + return; + deleted_flag = NULL; + QMutexLocker locker( &signal_mutex ); + if( emit_pending ) + { + emit_pending = false; + signal_cond.wakeOne(); + } + } + +#include "tsthread.moc" diff --git a/src/tsthread/tsthread.h b/src/tsthread/tsthread.h new file mode 100644 index 0000000..5b98890 --- /dev/null +++ b/src/tsthread/tsthread.h @@ -0,0 +1,387 @@ +/**************************************************************************** + + Copyright (C) 2004 Lubos Lunak + +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, sublicense, +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 OR COPYRIGHT HOLDERS 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. + +****************************************************************************/ + +#ifndef TSTHREAD_H +#define TSTHREAD_H + +#include +#include +#include +#include +#include +#include + +#ifdef TS_QTHREADSTORAGE +#include +#else +#include +#endif + +#include "tswaitcondition.h" + +// how difficult ... +template< typename T > +T TSDeepCopy( const T& t ) +{ + return QDeepCopy< T >( t ); +} + +class TSCurrentThread; + +/** + Thread class, internally based on QThread, which intentionally doesn't have + dangerous crap like QThread::terminate() and intentionally has useful features + like emitting signals to the main thread, currentThread() or support + for cancelling. + */ +class TSThread + : public QObject + { + Q_OBJECT + public: + TSThread(); + virtual ~TSThread(); + /** + * Starts the thread. + * @see QThread::start() + */ + void start(); + /** + * Waits for the thread to finish. + * @see QThread::wait() + */ + void wait( unsigned long time = ULONG_MAX ); + /** + * Returns true if the thread has finished. + * @see QThread::finished() + */ + bool finished() const; + /** + * Returns true if the thread is running. + * @see QThread::running() + */ + bool running() const; + /** + * Sends the thread a request to terminate. + * The thread must check for cancellation using testCancel() + * and finish execution (return from run()). + * @see testCancel() + */ + void cancel(); + // TODO suspend + resume? + /** + * Returns true if a request to terminate is pending. + * @see cancel() + */ + bool testCancel() const; + /** + * Returns pointer to the current thread, i.e. thread from which + * this function is called. + */ + static TSThread* currentThread(); + /** + * Returns a pointer to the main thread. Mostly useful for currentThread(). + */ + static TSThread* mainThread(); + /** + * Emits the specified signal in the main thread. This function returns + * only after all slots connected to the signal have been executed (i.e. + * it works like normal signal). The signal can have one pointer argument, + * which can be used for communication in either direction. QObject::sender() + * in slots is valid. + * Example: + * \code + * emitSignal( this, SIGNAL( result( int* )), &result_data ); + * \endcode + * @see postSignal + * @see emitCancellableSignal + */ + void emitSignal( QObject* obj, const char* signal ); + template< typename T1 > + void emitSignal( QObject* obj, const char* signal, const T1& p1 ); + template< typename T1, typename T2 > + void emitSignal( QObject* obj, const char* signal, const T1& p1, const T2& p2 ); + /** + * This function works like emitSignal(), but additionally acts as a cancellation + * point, i.e. calling cancel() on the thread causes premature return. + * @see emitSignal + * @see postSignal + */ + void emitCancellableSignal( QObject* obj, const char* signal ); + template< typename T1 > + void emitCancellableSignal( QObject* obj, const char* signal, const T1& p1 ); + template< typename T1, typename T2 > + void emitCancellableSignal( QObject* obj, const char* signal, const T1& p1, const T2& p2 ); + /** + * Posts (i.e. it is not executed immediatelly like normal signals) + * a signal to be emitted in the main thread. The signal cannot + * have any parameters, use your TSThread derived class instance + * data members instead. QObject::sender() in slots is valid, unless + * the thread instance is destroyed before the signal is processed. + * @see emitSignal + */ + void postSignal( QObject* obj, const char* signal ); // is emitted _always_ in main thread + protected: + /** + * The code to be executed in the started thread. + * @see QThread::run() + */ + virtual void run() = 0; + signals: + /** + * Emitted after the thread is terminated. + */ + void terminated(); // is emitted _always_ in main thread + protected: + /** + * @internal + */ + void customEvent( QCustomEvent* e ); + private: + class SignalEvent + : public QCustomEvent + { + public: + SignalEvent( const char* sig, QObject* obj, QUObject* o ) + : QCustomEvent( QEvent::User ), signal( sig ), object( obj ), args( o ) + { + } + const QCString signal; + QObject* object; + QUObject* args; + }; + class Helper + : public QThread + { + public: + Helper( TSThread* parent ); + protected: + virtual void run(); + private: + TSThread* thread; + }; + void executeThread(); + static void initCurrentThread(); + bool setCancelData( QMutex*m, QWaitCondition* c ); + void setSignalData( QUObject* o, int i ); + void setSignalData( QUObject* o, const QImage& i ); + void setSignalData( QUObject* o, const QString& s ); + void setSignalData( QUObject* o, bool b ); + void setSignalData( QUObject* o, const QColor& c ); + void setSignalData( QUObject* o, const char* s ); + void setSignalData( QUObject* o, const QSize& ); + void emitSignalInternal( QObject* obj, const char* signal, QUObject* o ); + void emitCancellableSignalInternal( QObject* obj, const char* signal, QUObject* o ); + friend class Helper; + friend class TSWaitCondition; + Helper thread; + bool cancelling; + bool emit_pending; + mutable QMutex mutex; + QMutex signal_mutex; + TSWaitCondition signal_cond; + QMutex* cancel_mutex; + QWaitCondition* cancel_cond; + bool* deleted_flag; +#ifdef TS_QTHREADSTORAGE + static QThreadStorage< TSThread** >* current_thread; +#else + static TSCurrentThread* current_thread; +#endif + static TSThread* main_thread; + private: + TSThread( const TSThread& ); + TSThread& operator=( const TSThread& ); + }; + +#ifndef TS_QTHREADSTORAGE +/** + * @internal + */ +class TSCurrentThread + { + public: + TSCurrentThread(); + ~TSCurrentThread(); + TSThread* localData() const; + void setLocalData( TSThread* t ); + private: + pthread_key_t key; + }; + + +inline TSCurrentThread::TSCurrentThread() + { + pthread_key_create( &key, NULL ); + } + +inline TSCurrentThread::~TSCurrentThread() + { + pthread_key_delete( key ); + } + +inline void TSCurrentThread::setLocalData( TSThread* t ) + { + pthread_setspecific( key, t ); + } + +inline TSThread* TSCurrentThread::localData() const + { + return static_cast< TSThread* >( pthread_getspecific( key )); + } +#endif + +inline +bool TSThread::testCancel() const + { + QMutexLocker lock( &mutex ); + return cancelling; + } + +#include +inline +bool TSThread::setCancelData( QMutex* m, QWaitCondition* c ) + { + QMutexLocker lock( &mutex ); + if( cancelling && m != NULL ) + return false; + cancel_mutex = m; + cancel_cond = c; + return true; + } + +inline +TSThread* TSThread::currentThread() + { + if( current_thread == NULL ) + initCurrentThread(); +#ifdef TS_QTHREADSTORAGE + return *current_thread->localData(); +#else + return current_thread->localData(); +#endif + } + +inline +TSThread* TSThread::mainThread() + { + return main_thread; + } + +inline +void TSThread::setSignalData( QUObject* o, int i ) + { + static_QUType_int.set( o, i ); + } + +inline +void TSThread::setSignalData( QUObject* o, const QImage& i ) + { + static_QUType_varptr.set( o, &i ); + } + +inline +void TSThread::setSignalData( QUObject* o, const QString& s ) + { + static_QUType_QString.set( o, s ); + } + +inline +void TSThread::setSignalData( QUObject* o, bool b ) + { + static_QUType_bool.set( o, b ); + } + +inline +void TSThread::setSignalData( QUObject* o, const QColor& c ) + { + static_QUType_varptr.set( o, &c ); + } + +inline +void TSThread::setSignalData( QUObject* o, const char* s ) + { + static_QUType_charstar.set( o, s ); + } + +inline +void TSThread::setSignalData( QUObject* o, const QSize& s ) + { + static_QUType_varptr.set( o, &s ); + } + +inline +void TSThread::emitSignal( QObject* obj, const char* signal ) + { + QUObject o[ 1 ]; + emitSignalInternal( obj, signal, o ); + } + +template< typename T1 > +inline +void TSThread::emitSignal( QObject* obj, const char* signal, const T1& p1 ) + { + QUObject o[ 2 ]; + setSignalData( o + 1, p1 ); + emitSignalInternal( obj, signal, o ); + } + +template< typename T1, typename T2 > +inline +void TSThread::emitSignal( QObject* obj, const char* signal, const T1& p1, const T2& p2 ) + { + QUObject o[ 3 ]; + setSignalData( o + 1, p1 ); + setSignalData( o + 2, p2 ); + emitSignalInternal( obj, signal, o ); + } + +inline +void TSThread::emitCancellableSignal( QObject* obj, const char* signal ) + { + QUObject o[ 1 ]; + emitCancellableSignalInternal( obj, signal, o ); + } + +template< typename T1 > +inline +void TSThread::emitCancellableSignal( QObject* obj, const char* signal, const T1& p1 ) + { + QUObject o[ 2 ]; + setSignalData( o + 1, p1 ); + emitCancellableSignalInternal( obj, signal, o ); + } + +template< typename T1, typename T2 > +inline +void TSThread::emitCancellableSignal( QObject* obj, const char* signal, const T1& p1, const T2& p2 ) + { + QUObject o[ 3 ]; + setSignalData( o + 1, p1 ); + setSignalData( o + 2, p2 ); + emitCancellableSignalInternal( obj, signal, o ); + } + + +#endif diff --git a/src/tsthread/tswaitcondition.cpp b/src/tsthread/tswaitcondition.cpp new file mode 100644 index 0000000..e11e989 --- /dev/null +++ b/src/tsthread/tswaitcondition.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** + + Copyright (C) 2004 Lubos Lunak + +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, sublicense, +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 OR COPYRIGHT HOLDERS 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 "tswaitcondition.h" + +#include "tsthread.h" + +bool TSWaitCondition::wait( QMutex* m, unsigned long time ) + { + return cond.wait( m, time ); // TODO? + } + +bool TSWaitCondition::cancellableWait( QMutex* m, unsigned long time ) + { + mutex.lock(); + if( !TSThread::currentThread()->setCancelData( &mutex, &cond )) + { + mutex.unlock(); + return false; + } + m->unlock(); + bool ret = cond.wait( &mutex, time ); + TSThread::currentThread()->setCancelData( NULL, NULL ); + mutex.unlock(); + m->lock(); + return ret; + } + +void TSWaitCondition::wakeOne() + { + QMutexLocker locker( &mutex ); + cond.wakeOne(); + } + +void TSWaitCondition::wakeAll() + { + QMutexLocker locker( &mutex ); + cond.wakeAll(); + } diff --git a/src/tsthread/tswaitcondition.h b/src/tsthread/tswaitcondition.h new file mode 100644 index 0000000..09f9cab --- /dev/null +++ b/src/tsthread/tswaitcondition.h @@ -0,0 +1,72 @@ +/**************************************************************************** + + Copyright (C) 2004 Lubos Lunak + +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, sublicense, +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 OR COPYRIGHT HOLDERS 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. + +****************************************************************************/ + +#ifndef TSWAITCONDITION_H +#define TSWAITCONDITION_H + +#include +#include + +class TSWaitCondition + { + public: + TSWaitCondition(); + ~TSWaitCondition(); + bool wait( QMutex* mutex, unsigned long time = ULONG_MAX ); + bool wait( QMutex& mutex, unsigned long time = ULONG_MAX ); + bool cancellableWait( QMutex* mutex, unsigned long time = ULONG_MAX ); + bool cancellableWait( QMutex& mutex, unsigned long time = ULONG_MAX ); + void wakeOne(); + void wakeAll(); + private: + QMutex mutex; + QWaitCondition cond; + private: + TSWaitCondition( const TSWaitCondition& ); + TSWaitCondition& operator=( const TSWaitCondition& ); + }; + +inline +TSWaitCondition::TSWaitCondition() + { + } + +inline +TSWaitCondition::~TSWaitCondition() + { + } + +inline +bool TSWaitCondition::wait( QMutex& mutex, unsigned long time ) + { + return wait( &mutex, time ); + } + +inline +bool TSWaitCondition::cancellableWait( QMutex& mutex, unsigned long time ) + { + return cancellableWait( &mutex, time ); + } + +#endif diff --git a/src/updates/Makefile.am b/src/updates/Makefile.am new file mode 100644 index 0000000..c246428 --- /dev/null +++ b/src/updates/Makefile.am @@ -0,0 +1,9 @@ +update_DATA = \ + gwenview_thumbnail_size.upd \ + gwenview_1.4_osdformat.upd + +update_SCRIPTS = \ + gwenview_thumbnail_size.sh \ + gwenview_1.4_osdformat.sh + +updatedir = $(kde_datadir)/kconf_update diff --git a/src/updates/gwenview_1.4_osdformat.sh b/src/updates/gwenview_1.4_osdformat.sh new file mode 100755 index 0000000..6a28550 --- /dev/null +++ b/src/updates/gwenview_1.4_osdformat.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +# Escape backslashes. Shell sucks. +sed s'/\\/BACKSLASH/g' | ( + +osdMode= +while read line ; do + if echo $line | grep '^osd mode' >/dev/null 2>/dev/null ; then + osdMode=$(echo $line | sed 's/^.*=//') + continue + fi + if echo $line | grep '^free output format' >/dev/null 2>/dev/null ; then + freeOutputFormat=$(echo $line | sed -e 's/^.*=//') + continue + fi + echo $line +done + +case $osdMode in + 0) + osdFormat='' + ;; + 1) + osdFormat='%p' + ;; + 2) + osdFormat='%c' + ;; + 3) + osdFormat='%p\\n%c' + ;; + 4) + osdFormat="$freeOutputFormat" + ;; + *) + osdFormat='' + ;; +esac + +echo osdFormat=$osdFormat + +) | sed 's/BACKSLASH/\\/g' +# Escape backslashes. Shell sucks. diff --git a/src/updates/gwenview_1.4_osdformat.upd b/src/updates/gwenview_1.4_osdformat.upd new file mode 100644 index 0000000..52f341d --- /dev/null +++ b/src/updates/gwenview_1.4_osdformat.upd @@ -0,0 +1,4 @@ +Id=osdformat +File=gwenviewrc +Group=pixmap widget +Script=gwenview_1.4_osdformat.sh,sh diff --git a/src/updates/gwenview_1.4_osdformat_test.sh b/src/updates/gwenview_1.4_osdformat_test.sh new file mode 100755 index 0000000..ed555d7 --- /dev/null +++ b/src/updates/gwenview_1.4_osdformat_test.sh @@ -0,0 +1,39 @@ +#!/bin/sh +check() { + cat > src.txt < tmp.txt < wanted.txt + ./gwenview_1.4_osdformat.sh < src.txt | sort > dst.txt + if diff -uwB --brief wanted.txt dst.txt ; then + echo ok + else + echo " +-------------- +# From: +$1 +# To: +$2 +# Got: +" + cat dst.txt + echo "# Wanted:" + cat wanted.txt + echo " +-------------- +" + fi +} + +check "osd mode=0" "osdFormat=" +check "osd mode=1" "osdFormat=%p" +check "osd mode=2" "osdFormat=%c" +check "osd mode=3" "osdFormat=%p\\n%c" +check "osd mode=3 +something else" "osdFormat=%p\\n%c +something else" +check "osd mode=4 +free output format=zog\\nzog" "osdFormat=zog\\nzog" diff --git a/src/updates/gwenview_thumbnail_size.sh b/src/updates/gwenview_thumbnail_size.sh new file mode 100644 index 0000000..5e2872b --- /dev/null +++ b/src/updates/gwenview_thumbnail_size.sh @@ -0,0 +1,12 @@ +#! /bin/sh +while read line; do + if echo "$line" | grep '^thumbnail size=small' >/dev/null 2>/dev/null; then + echo "thumbnail size=48" + elif echo "$line" | grep '^thumbnail size=med' >/dev/null 2>/dev/null; then + echo "thumbnail size=96" + elif echo "$line" | grep '^thumbnail size=large' >/dev/null 2>/dev/null; then + echo "thumbnail size=128" + else + echo "$line" + fi +done diff --git a/src/updates/gwenview_thumbnail_size.upd b/src/updates/gwenview_thumbnail_size.upd new file mode 100644 index 0000000..dea652b --- /dev/null +++ b/src/updates/gwenview_thumbnail_size.upd @@ -0,0 +1,5 @@ +Id=gwenview_thumbnail_size +File=gwenviewrc +Group=file widget +Options=overwrite +Script=gwenview_thumbnail_size.sh,sh diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 0000000..e69de29 diff --git a/subdirs b/subdirs new file mode 100644 index 0000000..1e0df52 --- /dev/null +++ b/subdirs @@ -0,0 +1,2 @@ +doc +src -- cgit v1.2.1