summaryrefslogtreecommitdiffstats
path: root/demos
diff options
context:
space:
mode:
authoraxis <qt-info@nokia.com>2009-04-24 11:34:15 (GMT)
committeraxis <qt-info@nokia.com>2009-04-24 11:34:15 (GMT)
commit8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76 (patch)
treea17e1a767a89542ab59907462206d7dcf2e504b2 /demos
downloadQt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.zip
Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.tar.gz
Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.tar.bz2
Long live Qt for S60!
Diffstat (limited to 'demos')
-rw-r--r--demos/README39
-rw-r--r--demos/affine/affine.pro25
-rw-r--r--demos/affine/affine.qrc7
-rw-r--r--demos/affine/bg1.jpgbin0 -> 23771 bytes
-rw-r--r--demos/affine/main.cpp63
-rw-r--r--demos/affine/xform.cpp902
-rw-r--r--demos/affine/xform.h141
-rw-r--r--demos/affine/xform.html23
-rw-r--r--demos/arthurplugin/arthur_plugin.qrc7
-rw-r--r--demos/arthurplugin/arthurplugin.pro53
-rw-r--r--demos/arthurplugin/bg1.jpgbin0 -> 23771 bytes
-rw-r--r--demos/arthurplugin/flower.jpgbin0 -> 49616 bytes
-rw-r--r--demos/arthurplugin/flower_alpha.jpgbin0 -> 67326 bytes
-rw-r--r--demos/arthurplugin/plugin.cpp262
-rw-r--r--demos/books/bookdelegate.cpp126
-rw-r--r--demos/books/bookdelegate.h73
-rw-r--r--demos/books/books.pro23
-rw-r--r--demos/books/books.qrc5
-rw-r--r--demos/books/bookwindow.cpp121
-rw-r--r--demos/books/bookwindow.h64
-rw-r--r--demos/books/bookwindow.ui149
-rw-r--r--demos/books/images/star.pngbin0 -> 782 bytes
-rw-r--r--demos/books/initdb.h125
-rw-r--r--demos/books/main.cpp56
-rw-r--r--demos/boxes/3rdparty/fbm.c207
-rw-r--r--demos/boxes/3rdparty/fbm.h40
-rw-r--r--demos/boxes/basic.fsh73
-rw-r--r--demos/boxes/basic.vsh61
-rw-r--r--demos/boxes/boxes.pro50
-rw-r--r--demos/boxes/boxes.qrc25
-rw-r--r--demos/boxes/cubemap_negx.jpgbin0 -> 41060 bytes
-rw-r--r--demos/boxes/cubemap_negy.jpgbin0 -> 15520 bytes
-rw-r--r--demos/boxes/cubemap_negz.jpgbin0 -> 68911 bytes
-rw-r--r--demos/boxes/cubemap_posx.jpgbin0 -> 74915 bytes
-rw-r--r--demos/boxes/cubemap_posy.jpgbin0 -> 24193 bytes
-rw-r--r--demos/boxes/cubemap_posz.jpgbin0 -> 57881 bytes
-rw-r--r--demos/boxes/dotted.fsh66
-rw-r--r--demos/boxes/fresnel.fsh79
-rw-r--r--demos/boxes/glass.fsh76
-rw-r--r--demos/boxes/glbuffers.cpp390
-rw-r--r--demos/boxes/glbuffers.h362
-rw-r--r--demos/boxes/glextensions.cpp135
-rw-r--r--demos/boxes/glextensions.h284
-rw-r--r--demos/boxes/glshaders.cpp266
-rw-r--r--demos/boxes/glshaders.h108
-rw-r--r--demos/boxes/gltrianglemesh.h91
-rw-r--r--demos/boxes/granite.fsh76
-rw-r--r--demos/boxes/main.cpp149
-rw-r--r--demos/boxes/marble.fsh71
-rw-r--r--demos/boxes/parameters.par5
-rw-r--r--demos/boxes/qt-logo.jpgbin0 -> 40886 bytes
-rw-r--r--demos/boxes/qt-logo.pngbin0 -> 13923 bytes
-rw-r--r--demos/boxes/qtbox.cpp469
-rw-r--r--demos/boxes/qtbox.h116
-rw-r--r--demos/boxes/reflection.fsh54
-rw-r--r--demos/boxes/refraction.fsh70
-rw-r--r--demos/boxes/roundedbox.cpp160
-rw-r--r--demos/boxes/roundedbox.h71
-rw-r--r--demos/boxes/scene.cpp1057
-rw-r--r--demos/boxes/scene.h243
-rw-r--r--demos/boxes/smiley.pngbin0 -> 14508 bytes
-rw-r--r--demos/boxes/square.jpgbin0 -> 14542 bytes
-rw-r--r--demos/boxes/trackball.cpp158
-rw-r--r--demos/boxes/trackball.h78
-rw-r--r--demos/boxes/vector.h602
-rw-r--r--demos/boxes/wood.fsh70
-rw-r--r--demos/browser/Info_mac.plist43
-rw-r--r--demos/browser/addbookmarkdialog.ui98
-rw-r--r--demos/browser/autosaver.cpp94
-rw-r--r--demos/browser/autosaver.h76
-rw-r--r--demos/browser/bookmarks.cpp987
-rw-r--r--demos/browser/bookmarks.h310
-rw-r--r--demos/browser/bookmarks.ui106
-rw-r--r--demos/browser/browser.icnsbin0 -> 50218 bytes
-rw-r--r--demos/browser/browser.icobin0 -> 15374 bytes
-rw-r--r--demos/browser/browser.pro93
-rw-r--r--demos/browser/browser.rc2
-rw-r--r--demos/browser/browserapplication.cpp456
-rw-r--r--demos/browser/browserapplication.h119
-rw-r--r--demos/browser/browsermainwindow.cpp991
-rw-r--r--demos/browser/browsermainwindow.h169
-rw-r--r--demos/browser/chasewidget.cpp142
-rw-r--r--demos/browser/chasewidget.h85
-rw-r--r--demos/browser/cookiejar.cpp733
-rw-r--r--demos/browser/cookiejar.h204
-rw-r--r--demos/browser/cookies.ui106
-rw-r--r--demos/browser/cookiesexceptions.ui184
-rw-r--r--demos/browser/data/addtab.pngbin0 -> 469 bytes
-rw-r--r--demos/browser/data/browser.svg411
-rw-r--r--demos/browser/data/closetab.pngbin0 -> 516 bytes
-rw-r--r--demos/browser/data/data.qrc11
-rw-r--r--demos/browser/data/defaultbookmarks.xbel40
-rw-r--r--demos/browser/data/defaulticon.pngbin0 -> 1473 bytes
-rw-r--r--demos/browser/data/history.pngbin0 -> 1527 bytes
-rw-r--r--demos/browser/data/loading.gifbin0 -> 847 bytes
-rw-r--r--demos/browser/downloaditem.ui134
-rw-r--r--demos/browser/downloadmanager.cpp579
-rw-r--r--demos/browser/downloadmanager.h162
-rw-r--r--demos/browser/downloads.ui83
-rw-r--r--demos/browser/edittableview.cpp78
-rw-r--r--demos/browser/edittableview.h61
-rw-r--r--demos/browser/edittreeview.cpp77
-rw-r--r--demos/browser/edittreeview.h61
-rw-r--r--demos/browser/history.cpp1282
-rw-r--r--demos/browser/history.h350
-rw-r--r--demos/browser/history.ui106
-rw-r--r--demos/browser/htmls/htmls.qrc5
-rw-r--r--demos/browser/htmls/notfound.html63
-rw-r--r--demos/browser/main.cpp53
-rw-r--r--demos/browser/modelmenu.cpp227
-rw-r--r--demos/browser/modelmenu.h105
-rw-r--r--demos/browser/networkaccessmanager.cpp171
-rw-r--r--demos/browser/networkaccessmanager.h68
-rw-r--r--demos/browser/passworddialog.ui111
-rw-r--r--demos/browser/proxy.ui104
-rw-r--r--demos/browser/searchlineedit.cpp238
-rw-r--r--demos/browser/searchlineedit.h103
-rw-r--r--demos/browser/settings.cpp324
-rw-r--r--demos/browser/settings.h74
-rw-r--r--demos/browser/settings.ui614
-rw-r--r--demos/browser/squeezelabel.cpp61
-rw-r--r--demos/browser/squeezelabel.h60
-rw-r--r--demos/browser/tabwidget.cpp830
-rw-r--r--demos/browser/tabwidget.h224
-rw-r--r--demos/browser/toolbarsearch.cpp161
-rw-r--r--demos/browser/toolbarsearch.h84
-rw-r--r--demos/browser/urllineedit.cpp340
-rw-r--r--demos/browser/urllineedit.h115
-rw-r--r--demos/browser/webview.cpp304
-rw-r--r--demos/browser/webview.h119
-rw-r--r--demos/browser/xbel.cpp320
-rw-r--r--demos/browser/xbel.h113
-rw-r--r--demos/chip/chip.cpp182
-rw-r--r--demos/chip/chip.h68
-rw-r--r--demos/chip/chip.pro21
-rw-r--r--demos/chip/fileprint.pngbin0 -> 1456 bytes
-rw-r--r--demos/chip/images.qrc10
-rw-r--r--demos/chip/main.cpp57
-rw-r--r--demos/chip/mainwindow.cpp109
-rw-r--r--demos/chip/mainwindow.h68
-rw-r--r--demos/chip/qt4logo.pngbin0 -> 48333 bytes
-rw-r--r--demos/chip/rotateleft.pngbin0 -> 1754 bytes
-rw-r--r--demos/chip/rotateright.pngbin0 -> 1732 bytes
-rw-r--r--demos/chip/view.cpp234
-rw-r--r--demos/chip/view.h84
-rw-r--r--demos/chip/zoomin.pngbin0 -> 1622 bytes
-rw-r--r--demos/chip/zoomout.pngbin0 -> 1601 bytes
-rw-r--r--demos/composition/composition.cpp511
-rw-r--r--demos/composition/composition.h190
-rw-r--r--demos/composition/composition.html23
-rw-r--r--demos/composition/composition.pro29
-rw-r--r--demos/composition/composition.qrc8
-rw-r--r--demos/composition/flower.jpgbin0 -> 49616 bytes
-rw-r--r--demos/composition/flower_alpha.jpgbin0 -> 67326 bytes
-rw-r--r--demos/composition/main.cpp62
-rw-r--r--demos/deform/deform.pro23
-rw-r--r--demos/deform/deform.qrc6
-rw-r--r--demos/deform/main.cpp72
-rw-r--r--demos/deform/pathdeform.cpp659
-rw-r--r--demos/deform/pathdeform.h153
-rw-r--r--demos/deform/pathdeform.html24
-rw-r--r--demos/demobase.pri1
-rw-r--r--demos/demos.pro80
-rw-r--r--demos/embedded/desktopservices/contenttab.cpp110
-rw-r--r--demos/embedded/desktopservices/contenttab.h68
-rw-r--r--demos/embedded/desktopservices/data/Explosion.wavbin0 -> 18427 bytes
-rw-r--r--demos/embedded/desktopservices/data/designer.pngbin0 -> 4205 bytes
-rw-r--r--demos/embedded/desktopservices/data/monkey_on_64x64.pngbin0 -> 3479 bytes
-rw-r--r--demos/embedded/desktopservices/data/sax.mp3bin0 -> 417844 bytes
-rw-r--r--demos/embedded/desktopservices/desktopservices.pro23
-rw-r--r--demos/embedded/desktopservices/desktopservices.qrc8
-rw-r--r--demos/embedded/desktopservices/desktopwidget.cpp56
-rw-r--r--demos/embedded/desktopservices/desktopwidget.h41
-rw-r--r--demos/embedded/desktopservices/linktab.cpp49
-rw-r--r--demos/embedded/desktopservices/linktab.h53
-rw-r--r--demos/embedded/desktopservices/main.cpp26
-rw-r--r--demos/embedded/desktopservices/resources/browser.pngbin0 -> 2739 bytes
-rw-r--r--demos/embedded/desktopservices/resources/heart.svg55
-rw-r--r--demos/embedded/desktopservices/resources/message.pngbin0 -> 2234 bytes
-rw-r--r--demos/embedded/desktopservices/resources/music.pngbin0 -> 2322 bytes
-rw-r--r--demos/embedded/desktopservices/resources/photo.pngbin0 -> 2430 bytes
-rw-r--r--demos/embedded/embedded.pro16
-rw-r--r--demos/embedded/embeddedsvgviewer/embeddedsvgviewer.cpp181
-rw-r--r--demos/embedded/embeddedsvgviewer/embeddedsvgviewer.h87
-rw-r--r--demos/embedded/embeddedsvgviewer/embeddedsvgviewer.pro21
-rw-r--r--demos/embedded/embeddedsvgviewer/embeddedsvgviewer.qrc7
-rw-r--r--demos/embedded/embeddedsvgviewer/files/default.svg86
-rw-r--r--demos/embedded/embeddedsvgviewer/files/v-slider-handle.svg100
-rw-r--r--demos/embedded/embeddedsvgviewer/main.cpp68
-rw-r--r--demos/embedded/embeddedsvgviewer/shapes.svg86
-rw-r--r--demos/embedded/embeddedsvgviewer/spheres.svg81
-rw-r--r--demos/embedded/fluidlauncher/config.xml26
-rw-r--r--demos/embedded/fluidlauncher/config_s60/config.xml19
-rw-r--r--demos/embedded/fluidlauncher/config_wince/config.xml13
-rw-r--r--demos/embedded/fluidlauncher/demoapplication.cpp116
-rw-r--r--demos/embedded/fluidlauncher/demoapplication.h82
-rw-r--r--demos/embedded/fluidlauncher/fluidlauncher.cpp263
-rw-r--r--demos/embedded/fluidlauncher/fluidlauncher.h83
-rw-r--r--demos/embedded/fluidlauncher/fluidlauncher.pro138
-rw-r--r--demos/embedded/fluidlauncher/main.cpp60
-rw-r--r--demos/embedded/fluidlauncher/pictureflow.cpp1434
-rw-r--r--demos/embedded/fluidlauncher/pictureflow.h237
-rw-r--r--demos/embedded/fluidlauncher/screenshots/concentriccircles.pngbin0 -> 29623 bytes
-rw-r--r--demos/embedded/fluidlauncher/screenshots/context2d.pngbin0 -> 23995 bytes
-rw-r--r--demos/embedded/fluidlauncher/screenshots/deform.pngbin0 -> 18393 bytes
-rw-r--r--demos/embedded/fluidlauncher/screenshots/desktopservices.pngbin0 -> 43341 bytes
-rw-r--r--demos/embedded/fluidlauncher/screenshots/elasticnodes.pngbin0 -> 13312 bytes
-rw-r--r--demos/embedded/fluidlauncher/screenshots/embeddedsvgviewer.pngbin0 -> 7482 bytes
-rw-r--r--demos/embedded/fluidlauncher/screenshots/fridgemagnets.pngbin0 -> 50464 bytes
-rw-r--r--demos/embedded/fluidlauncher/screenshots/ftp.pngbin0 -> 29831 bytes
-rw-r--r--demos/embedded/fluidlauncher/screenshots/mediaplayer.pngbin0 -> 7217 bytes
-rw-r--r--demos/embedded/fluidlauncher/screenshots/pathstroke.pngbin0 -> 14216 bytes
-rw-r--r--demos/embedded/fluidlauncher/screenshots/saxbookmarks.pngbin0 -> 27098 bytes
-rw-r--r--demos/embedded/fluidlauncher/screenshots/styledemo.pngbin0 -> 26891 bytes
-rw-r--r--demos/embedded/fluidlauncher/screenshots/wiggly.pngbin0 -> 6546 bytes
-rw-r--r--demos/embedded/fluidlauncher/slides/demo_1.pngbin0 -> 23539 bytes
-rw-r--r--demos/embedded/fluidlauncher/slides/demo_2.pngbin0 -> 11745 bytes
-rw-r--r--demos/embedded/fluidlauncher/slides/demo_3.pngbin0 -> 19791 bytes
-rw-r--r--demos/embedded/fluidlauncher/slides/demo_4.pngbin0 -> 5505 bytes
-rw-r--r--demos/embedded/fluidlauncher/slides/demo_5.pngbin0 -> 15890 bytes
-rw-r--r--demos/embedded/fluidlauncher/slides/demo_6.pngbin0 -> 14992 bytes
-rw-r--r--demos/embedded/fluidlauncher/slideshow.cpp233
-rw-r--r--demos/embedded/fluidlauncher/slideshow.h97
-rwxr-xr-xdemos/embedded/styledemo/files/add.pngbin0 -> 1474 bytes
-rw-r--r--demos/embedded/styledemo/files/application.qss125
-rw-r--r--demos/embedded/styledemo/files/blue.qss38
-rw-r--r--demos/embedded/styledemo/files/khaki.qss99
-rw-r--r--demos/embedded/styledemo/files/nature_1.jpgbin0 -> 167443 bytes
-rw-r--r--demos/embedded/styledemo/files/nostyle.qss0
-rwxr-xr-xdemos/embedded/styledemo/files/remove.pngbin0 -> 865 bytes
-rw-r--r--demos/embedded/styledemo/files/transparent.qss139
-rw-r--r--demos/embedded/styledemo/main.cpp59
-rw-r--r--demos/embedded/styledemo/styledemo.pro16
-rw-r--r--demos/embedded/styledemo/styledemo.qrc13
-rw-r--r--demos/embedded/styledemo/stylewidget.cpp112
-rw-r--r--demos/embedded/styledemo/stylewidget.h65
-rw-r--r--demos/embedded/styledemo/stylewidget.ui435
-rw-r--r--demos/embeddeddialogs/No-Ones-Laughing-3.jpgbin0 -> 30730 bytes
-rw-r--r--demos/embeddeddialogs/customproxy.cpp156
-rw-r--r--demos/embeddeddialogs/customproxy.h75
-rw-r--r--demos/embeddeddialogs/embeddeddialog.cpp106
-rw-r--r--demos/embeddeddialogs/embeddeddialog.h66
-rw-r--r--demos/embeddeddialogs/embeddeddialog.ui87
-rw-r--r--demos/embeddeddialogs/embeddeddialogs.pro19
-rw-r--r--demos/embeddeddialogs/embeddeddialogs.qrc5
-rw-r--r--demos/embeddeddialogs/main.cpp85
-rw-r--r--demos/gradients/gradients.cpp516
-rw-r--r--demos/gradients/gradients.h170
-rw-r--r--demos/gradients/gradients.html31
-rw-r--r--demos/gradients/gradients.pro20
-rw-r--r--demos/gradients/gradients.qrc6
-rw-r--r--demos/gradients/main.cpp61
-rw-r--r--demos/interview/README2
-rw-r--r--demos/interview/images/folder.pngbin0 -> 3910 bytes
-rw-r--r--demos/interview/images/interview.pngbin0 -> 174 bytes
-rw-r--r--demos/interview/images/services.pngbin0 -> 3749 bytes
-rw-r--r--demos/interview/interview.pro20
-rw-r--r--demos/interview/interview.qrc7
-rw-r--r--demos/interview/main.cpp95
-rw-r--r--demos/interview/model.cpp147
-rw-r--r--demos/interview/model.h88
-rw-r--r--demos/macmainwindow/macmainwindow.h137
-rw-r--r--demos/macmainwindow/macmainwindow.mm347
-rw-r--r--demos/macmainwindow/macmainwindow.pro25
-rw-r--r--demos/macmainwindow/main.cpp66
-rw-r--r--demos/mainwindow/colorswatch.cpp746
-rw-r--r--demos/mainwindow/colorswatch.h136
-rw-r--r--demos/mainwindow/main.cpp164
-rw-r--r--demos/mainwindow/mainwindow.cpp510
-rw-r--r--demos/mainwindow/mainwindow.h90
-rw-r--r--demos/mainwindow/mainwindow.pro18
-rw-r--r--demos/mainwindow/mainwindow.qrc8
-rw-r--r--demos/mainwindow/qt.pngbin0 -> 2037 bytes
-rw-r--r--demos/mainwindow/titlebarCenter.pngbin0 -> 146 bytes
-rw-r--r--demos/mainwindow/titlebarLeft.pngbin0 -> 5148 bytes
-rw-r--r--demos/mainwindow/titlebarRight.pngbin0 -> 2704 bytes
-rw-r--r--demos/mainwindow/toolbar.cpp383
-rw-r--r--demos/mainwindow/toolbar.h118
-rw-r--r--demos/mediaplayer/images/screen.pngbin0 -> 4358 bytes
-rw-r--r--demos/mediaplayer/main.cpp59
-rw-r--r--demos/mediaplayer/mediaplayer.cpp840
-rw-r--r--demos/mediaplayer/mediaplayer.h137
-rw-r--r--demos/mediaplayer/mediaplayer.pro28
-rw-r--r--demos/mediaplayer/mediaplayer.qrc5
-rw-r--r--demos/mediaplayer/settings.ui464
-rw-r--r--demos/pathstroke/main.cpp69
-rw-r--r--demos/pathstroke/pathstroke.cpp599
-rw-r--r--demos/pathstroke/pathstroke.h168
-rw-r--r--demos/pathstroke/pathstroke.html20
-rw-r--r--demos/pathstroke/pathstroke.pro23
-rw-r--r--demos/pathstroke/pathstroke.qrc6
-rw-r--r--demos/qtdemo/Info_mac.plist18
-rw-r--r--demos/qtdemo/colors.cpp390
-rw-r--r--demos/qtdemo/colors.h130
-rw-r--r--demos/qtdemo/demoitem.cpp280
-rw-r--r--demos/qtdemo/demoitem.h124
-rw-r--r--demos/qtdemo/demoitemanimation.cpp219
-rw-r--r--demos/qtdemo/demoitemanimation.h101
-rw-r--r--demos/qtdemo/demoscene.cpp54
-rw-r--r--demos/qtdemo/demoscene.h57
-rw-r--r--demos/qtdemo/demotextitem.cpp123
-rw-r--r--demos/qtdemo/demotextitem.h74
-rw-r--r--demos/qtdemo/dockitem.cpp108
-rw-r--r--demos/qtdemo/dockitem.h69
-rw-r--r--demos/qtdemo/examplecontent.cpp158
-rw-r--r--demos/qtdemo/examplecontent.h77
-rw-r--r--demos/qtdemo/guide.cpp144
-rw-r--r--demos/qtdemo/guide.h73
-rw-r--r--demos/qtdemo/guidecircle.cpp88
-rw-r--r--demos/qtdemo/guidecircle.h72
-rw-r--r--demos/qtdemo/guideline.cpp81
-rw-r--r--demos/qtdemo/guideline.h65
-rw-r--r--demos/qtdemo/headingitem.cpp104
-rw-r--r--demos/qtdemo/headingitem.h63
-rw-r--r--demos/qtdemo/imageitem.cpp114
-rw-r--r--demos/qtdemo/imageitem.h66
-rwxr-xr-xdemos/qtdemo/images/demobg.pngbin0 -> 20675 bytes
-rw-r--r--demos/qtdemo/images/qtlogo_small.pngbin0 -> 3546 bytes
-rw-r--r--demos/qtdemo/images/trolltech-logo.pngbin0 -> 23547 bytes
-rw-r--r--demos/qtdemo/itemcircleanimation.cpp507
-rw-r--r--demos/qtdemo/itemcircleanimation.h110
-rw-r--r--demos/qtdemo/letteritem.cpp85
-rw-r--r--demos/qtdemo/letteritem.h62
-rw-r--r--demos/qtdemo/main.cpp74
-rw-r--r--demos/qtdemo/mainwindow.cpp483
-rw-r--r--demos/qtdemo/mainwindow.h109
-rw-r--r--demos/qtdemo/menucontent.cpp140
-rw-r--r--demos/qtdemo/menucontent.h77
-rw-r--r--demos/qtdemo/menumanager.cpp876
-rw-r--r--demos/qtdemo/menumanager.h134
-rw-r--r--demos/qtdemo/qtdemo.icnsbin0 -> 129539 bytes
-rw-r--r--demos/qtdemo/qtdemo.icobin0 -> 355574 bytes
-rw-r--r--demos/qtdemo/qtdemo.pro74
-rw-r--r--demos/qtdemo/qtdemo.qrc8
-rw-r--r--demos/qtdemo/qtdemo.rc2
-rw-r--r--demos/qtdemo/scanitem.cpp80
-rw-r--r--demos/qtdemo/scanitem.h60
-rw-r--r--demos/qtdemo/score.cpp149
-rw-r--r--demos/qtdemo/score.h86
-rw-r--r--demos/qtdemo/textbutton.cpp384
-rw-r--r--demos/qtdemo/textbutton.h100
-rw-r--r--demos/qtdemo/xml/examples.xml227
-rw-r--r--demos/shared/arthurstyle.cpp452
-rw-r--r--demos/shared/arthurstyle.h79
-rw-r--r--demos/shared/arthurwidgets.cpp371
-rw-r--r--demos/shared/arthurwidgets.h118
-rw-r--r--demos/shared/hoverpoints.cpp333
-rw-r--r--demos/shared/hoverpoints.h160
-rw-r--r--demos/shared/images/bg_pattern.pngbin0 -> 104 bytes
-rw-r--r--demos/shared/images/button_normal_cap_left.pngbin0 -> 654 bytes
-rw-r--r--demos/shared/images/button_normal_cap_right.pngbin0 -> 674 bytes
-rw-r--r--demos/shared/images/button_normal_stretch.pngbin0 -> 185 bytes
-rw-r--r--demos/shared/images/button_pressed_cap_left.pngbin0 -> 710 bytes
-rw-r--r--demos/shared/images/button_pressed_cap_right.pngbin0 -> 785 bytes
-rw-r--r--demos/shared/images/button_pressed_stretch.pngbin0 -> 217 bytes
-rw-r--r--demos/shared/images/curve_thing_edit-6.pngbin0 -> 58097 bytes
-rw-r--r--demos/shared/images/frame_bottom.pngbin0 -> 166 bytes
-rw-r--r--demos/shared/images/frame_bottomleft.pngbin0 -> 602 bytes
-rw-r--r--demos/shared/images/frame_bottomright.pngbin0 -> 553 bytes
-rw-r--r--demos/shared/images/frame_left.pngbin0 -> 182 bytes
-rw-r--r--demos/shared/images/frame_right.pngbin0 -> 175 bytes
-rw-r--r--demos/shared/images/frame_top.pngbin0 -> 188 bytes
-rw-r--r--demos/shared/images/frame_topleft.pngbin0 -> 801 bytes
-rw-r--r--demos/shared/images/frame_topright.pngbin0 -> 851 bytes
-rw-r--r--demos/shared/images/groupframe_bottom_left.pngbin0 -> 397 bytes
-rw-r--r--demos/shared/images/groupframe_bottom_right.pngbin0 -> 383 bytes
-rw-r--r--demos/shared/images/groupframe_bottom_stretch.pngbin0 -> 141 bytes
-rw-r--r--demos/shared/images/groupframe_left_stretch.pngbin0 -> 132 bytes
-rw-r--r--demos/shared/images/groupframe_right_stretch.pngbin0 -> 113 bytes
-rw-r--r--demos/shared/images/groupframe_top_stretch.pngbin0 -> 115 bytes
-rw-r--r--demos/shared/images/groupframe_topleft.pngbin0 -> 412 bytes
-rw-r--r--demos/shared/images/groupframe_topright.pngbin0 -> 449 bytes
-rw-r--r--demos/shared/images/line_dash_dot.pngbin0 -> 151 bytes
-rw-r--r--demos/shared/images/line_dash_dot_dot.pngbin0 -> 155 bytes
-rw-r--r--demos/shared/images/line_dashed.pngbin0 -> 121 bytes
-rw-r--r--demos/shared/images/line_dotted.pngbin0 -> 116 bytes
-rw-r--r--demos/shared/images/line_solid.pngbin0 -> 110 bytes
-rw-r--r--demos/shared/images/radiobutton-off.pngbin0 -> 442 bytes
-rw-r--r--demos/shared/images/radiobutton-on.pngbin0 -> 474 bytes
-rw-r--r--demos/shared/images/radiobutton_off.pngbin0 -> 442 bytes
-rw-r--r--demos/shared/images/radiobutton_on.pngbin0 -> 499 bytes
-rw-r--r--demos/shared/images/slider_bar.pngbin0 -> 748 bytes
-rw-r--r--demos/shared/images/slider_thumb_off.pngbin0 -> 823 bytes
-rw-r--r--demos/shared/images/slider_thumb_on.pngbin0 -> 798 bytes
-rw-r--r--demos/shared/images/title_cap_left.pngbin0 -> 179 bytes
-rw-r--r--demos/shared/images/title_cap_right.pngbin0 -> 184 bytes
-rw-r--r--demos/shared/images/title_stretch.pngbin0 -> 106 bytes
-rw-r--r--demos/shared/shared.pri21
-rw-r--r--demos/shared/shared.pro36
-rw-r--r--demos/shared/shared.qrc39
-rw-r--r--demos/spreadsheet/images/interview.pngbin0 -> 174 bytes
-rw-r--r--demos/spreadsheet/main.cpp55
-rw-r--r--demos/spreadsheet/printview.cpp59
-rw-r--r--demos/spreadsheet/printview.h60
-rw-r--r--demos/spreadsheet/spreadsheet.cpp631
-rw-r--r--demos/spreadsheet/spreadsheet.h124
-rw-r--r--demos/spreadsheet/spreadsheet.pro35
-rw-r--r--demos/spreadsheet/spreadsheet.qrc5
-rw-r--r--demos/spreadsheet/spreadsheetdelegate.cpp114
-rw-r--r--demos/spreadsheet/spreadsheetdelegate.h65
-rw-r--r--demos/spreadsheet/spreadsheetitem.cpp167
-rw-r--r--demos/spreadsheet/spreadsheetitem.h73
-rw-r--r--demos/sqlbrowser/browser.cpp247
-rw-r--r--demos/sqlbrowser/browser.h99
-rw-r--r--demos/sqlbrowser/browserwidget.ui199
-rw-r--r--demos/sqlbrowser/connectionwidget.cpp165
-rw-r--r--demos/sqlbrowser/connectionwidget.h79
-rw-r--r--demos/sqlbrowser/main.cpp91
-rw-r--r--demos/sqlbrowser/qsqlconnectiondialog.cpp115
-rw-r--r--demos/sqlbrowser/qsqlconnectiondialog.h74
-rw-r--r--demos/sqlbrowser/qsqlconnectiondialog.ui224
-rw-r--r--demos/sqlbrowser/sqlbrowser.pro25
-rw-r--r--demos/textedit/example.html79
-rw-r--r--demos/textedit/images/logo32.pngbin0 -> 1410 bytes
-rw-r--r--demos/textedit/images/mac/editcopy.pngbin0 -> 1468 bytes
-rw-r--r--demos/textedit/images/mac/editcut.pngbin0 -> 1512 bytes
-rw-r--r--demos/textedit/images/mac/editpaste.pngbin0 -> 1906 bytes
-rw-r--r--demos/textedit/images/mac/editredo.pngbin0 -> 1752 bytes
-rw-r--r--demos/textedit/images/mac/editundo.pngbin0 -> 1746 bytes
-rw-r--r--demos/textedit/images/mac/exportpdf.pngbin0 -> 1215 bytes
-rw-r--r--demos/textedit/images/mac/filenew.pngbin0 -> 1172 bytes
-rw-r--r--demos/textedit/images/mac/fileopen.pngbin0 -> 2168 bytes
-rw-r--r--demos/textedit/images/mac/fileprint.pngbin0 -> 2087 bytes
-rw-r--r--demos/textedit/images/mac/filesave.pngbin0 -> 1206 bytes
-rw-r--r--demos/textedit/images/mac/textbold.pngbin0 -> 1611 bytes
-rw-r--r--demos/textedit/images/mac/textcenter.pngbin0 -> 1404 bytes
-rw-r--r--demos/textedit/images/mac/textitalic.pngbin0 -> 1164 bytes
-rw-r--r--demos/textedit/images/mac/textjustify.pngbin0 -> 1257 bytes
-rw-r--r--demos/textedit/images/mac/textleft.pngbin0 -> 1235 bytes
-rw-r--r--demos/textedit/images/mac/textright.pngbin0 -> 1406 bytes
-rw-r--r--demos/textedit/images/mac/textunder.pngbin0 -> 1183 bytes
-rw-r--r--demos/textedit/images/mac/zoomin.pngbin0 -> 1696 bytes
-rw-r--r--demos/textedit/images/mac/zoomout.pngbin0 -> 1662 bytes
-rw-r--r--demos/textedit/images/win/editcopy.pngbin0 -> 1325 bytes
-rw-r--r--demos/textedit/images/win/editcut.pngbin0 -> 1896 bytes
-rw-r--r--demos/textedit/images/win/editpaste.pngbin0 -> 1482 bytes
-rw-r--r--demos/textedit/images/win/editredo.pngbin0 -> 1787 bytes
-rw-r--r--demos/textedit/images/win/editundo.pngbin0 -> 1768 bytes
-rw-r--r--demos/textedit/images/win/exportpdf.pngbin0 -> 1059 bytes
-rw-r--r--demos/textedit/images/win/filenew.pngbin0 -> 768 bytes
-rw-r--r--demos/textedit/images/win/fileopen.pngbin0 -> 1662 bytes
-rw-r--r--demos/textedit/images/win/fileprint.pngbin0 -> 1456 bytes
-rw-r--r--demos/textedit/images/win/filesave.pngbin0 -> 1205 bytes
-rw-r--r--demos/textedit/images/win/textbold.pngbin0 -> 1134 bytes
-rw-r--r--demos/textedit/images/win/textcenter.pngbin0 -> 627 bytes
-rw-r--r--demos/textedit/images/win/textitalic.pngbin0 -> 829 bytes
-rw-r--r--demos/textedit/images/win/textjustify.pngbin0 -> 695 bytes
-rw-r--r--demos/textedit/images/win/textleft.pngbin0 -> 673 bytes
-rw-r--r--demos/textedit/images/win/textright.pngbin0 -> 677 bytes
-rw-r--r--demos/textedit/images/win/textunder.pngbin0 -> 971 bytes
-rw-r--r--demos/textedit/images/win/zoomin.pngbin0 -> 1208 bytes
-rw-r--r--demos/textedit/images/win/zoomout.pngbin0 -> 1226 bytes
-rw-r--r--demos/textedit/main.cpp54
-rw-r--r--demos/textedit/textedit.cpp694
-rw-r--r--demos/textedit/textedit.doc18
-rw-r--r--demos/textedit/textedit.h129
-rw-r--r--demos/textedit/textedit.pro23
-rw-r--r--demos/textedit/textedit.qrc44
-rw-r--r--demos/undo/commands.cpp180
-rw-r--r--demos/undo/commands.h112
-rw-r--r--demos/undo/document.cpp445
-rw-r--r--demos/undo/document.h125
-rw-r--r--demos/undo/icons/background.pngbin0 -> 93 bytes
-rw-r--r--demos/undo/icons/blue.pngbin0 -> 1659 bytes
-rw-r--r--demos/undo/icons/circle.pngbin0 -> 1359 bytes
-rw-r--r--demos/undo/icons/exit.pngbin0 -> 1731 bytes
-rw-r--r--demos/undo/icons/fileclose.pngbin0 -> 1121 bytes
-rw-r--r--demos/undo/icons/filenew.pngbin0 -> 1266 bytes
-rw-r--r--demos/undo/icons/fileopen.pngbin0 -> 1771 bytes
-rw-r--r--demos/undo/icons/filesave.pngbin0 -> 1022 bytes
-rw-r--r--demos/undo/icons/green.pngbin0 -> 1766 bytes
-rw-r--r--demos/undo/icons/ok.pngbin0 -> 979 bytes
-rw-r--r--demos/undo/icons/rectangle.pngbin0 -> 690 bytes
-rw-r--r--demos/undo/icons/red.pngbin0 -> 1653 bytes
-rw-r--r--demos/undo/icons/redo.pngbin0 -> 985 bytes
-rw-r--r--demos/undo/icons/remove.pngbin0 -> 1833 bytes
-rw-r--r--demos/undo/icons/triangle.pngbin0 -> 850 bytes
-rw-r--r--demos/undo/icons/undo.pngbin0 -> 962 bytes
-rw-r--r--demos/undo/main.cpp56
-rw-r--r--demos/undo/mainwindow.cpp446
-rw-r--r--demos/undo/mainwindow.h87
-rw-r--r--demos/undo/mainwindow.ui322
-rw-r--r--demos/undo/undo.pro19
-rw-r--r--demos/undo/undo.qrc20
484 files changed, 50023 insertions, 0 deletions
diff --git a/demos/README b/demos/README
new file mode 100644
index 0000000..b161990
--- /dev/null
+++ b/demos/README
@@ -0,0 +1,39 @@
+These demonstrations are intended to highlight Qt's capabilities in different
+application areas, and provide examples that are more advanced than those in
+the examples directory.
+
+Beginners to Qt may wish to try out the Qt tutorial and some of the examples
+before examining the demonstrations in detail.
+
+
+The example launcher can be used to explore the different categories
+available. It provides an overview of each example, lets you view the
+documentation in Qt Assistant, and is able to launch examples.
+
+
+Finding the Qt Examples and Demos launcher
+==========================================
+
+On Windows:
+
+The launcher can be accessed via the Windows Start menu. Select the menu
+entry entitled "Qt Examples and Demos" entry in the submenu containing
+the Qt tools.
+
+On Mac OS X:
+
+For the binary distribution, the qtdemo executable is installed in the
+/Developer/Applications/Qt directory. For the source distribution, it is
+installed alongside the other Qt tools on the path specified when Qt is
+configured.
+
+On Unix/Linux:
+
+The qtdemo executable is installed alongside the other Qt tools on the path
+specified when Qt is configured.
+
+On all platforms:
+
+The source code for the launcher can be found in the demos/qtdemo directory
+in the Qt package. This example is built at the same time as the Qt libraries,
+tools, examples, and demonstrations.
diff --git a/demos/affine/affine.pro b/demos/affine/affine.pro
new file mode 100644
index 0000000..4973496
--- /dev/null
+++ b/demos/affine/affine.pro
@@ -0,0 +1,25 @@
+SOURCES += main.cpp xform.cpp
+HEADERS += xform.h
+
+contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2) {
+ DEFINES += QT_OPENGL_SUPPORT
+ QT += opengl
+}
+
+SHARED_FOLDER = ../shared
+
+include($$SHARED_FOLDER/shared.pri)
+
+RESOURCES += affine.qrc
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/affine
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.html *.jpg
+sources.path = $$[QT_INSTALL_DEMOS]/affine
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
+wince*: {
+ DEPLOYMENT_PLUGIN += qjpeg
+}
diff --git a/demos/affine/affine.qrc b/demos/affine/affine.qrc
new file mode 100644
index 0000000..d8a7ae4
--- /dev/null
+++ b/demos/affine/affine.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/res/affine">
+ <file>xform.cpp</file>
+ <file>xform.html</file>
+ <file>bg1.jpg</file>
+</qresource>
+</RCC>
diff --git a/demos/affine/bg1.jpg b/demos/affine/bg1.jpg
new file mode 100644
index 0000000..dfc7cee
--- /dev/null
+++ b/demos/affine/bg1.jpg
Binary files differ
diff --git a/demos/affine/main.cpp b/demos/affine/main.cpp
new file mode 100644
index 0000000..88cd864
--- /dev/null
+++ b/demos/affine/main.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "xform.h"
+
+#include <QApplication>
+
+int main(int argc, char **argv)
+{
+ Q_INIT_RESOURCE(affine);
+
+ QApplication app(argc, argv);
+
+ XFormWidget xformWidget(0);
+ QStyle *arthurStyle = new ArthurStyle();
+ xformWidget.setStyle(arthurStyle);
+
+ QList<QWidget *> widgets = qFindChildren<QWidget *>(&xformWidget);
+ foreach (QWidget *w, widgets)
+ w->setStyle(arthurStyle);
+
+ xformWidget.show();
+
+ return app.exec();
+}
diff --git a/demos/affine/xform.cpp b/demos/affine/xform.cpp
new file mode 100644
index 0000000..059e38e
--- /dev/null
+++ b/demos/affine/xform.cpp
@@ -0,0 +1,902 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "xform.h"
+#include "hoverpoints.h"
+
+#include <QLayout>
+#include <QPainter>
+#include <QPainterPath>
+
+const int alpha = 155;
+
+XFormView::XFormView(QWidget *parent)
+ : ArthurFrame(parent)
+{
+ setAttribute(Qt::WA_MouseTracking);
+ m_type = VectorType;
+ m_rotation = 0.0;
+ m_scale = 1.0;
+ m_shear = 0.0;
+
+ m_pixmap = QPixmap(":res/affine/bg1.jpg");
+ pts = new HoverPoints(this, HoverPoints::CircleShape);
+ pts->setConnectionType(HoverPoints::LineConnection);
+ pts->setEditable(false);
+ pts->setPointSize(QSize(15, 15));
+ pts->setShapeBrush(QBrush(QColor(151, 0, 0, alpha)));
+ pts->setShapePen(QPen(QColor(255, 100, 50, alpha)));
+ pts->setConnectionPen(QPen(QColor(151, 0, 0, 50)));
+ pts->setBoundingRect(QRectF(0, 0, 500, 500));
+ ctrlPoints << QPointF(250, 250) << QPointF(350, 250);
+ pts->setPoints(ctrlPoints);
+ connect(pts, SIGNAL(pointsChanged(const QPolygonF&)),
+ this, SLOT(updateCtrlPoints(const QPolygonF &)));
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+}
+
+XFormView::XFormType XFormView::type() const
+{
+ return m_type;
+}
+
+QPixmap XFormView::pixmap() const
+{
+ return m_pixmap;
+}
+
+QString XFormView::text() const
+{
+ return m_text;
+}
+
+void XFormView::setText(const QString &t)
+{
+ m_text = t;
+ update();
+}
+
+void XFormView::setPixmap(const QPixmap &p)
+{
+ m_pixmap = p;
+ update();
+}
+
+void XFormView::setType(XFormType t)
+{
+ m_type = t;
+ update();
+}
+
+void XFormView::mousePressEvent(QMouseEvent *)
+{
+ setDescriptionEnabled(false);
+}
+
+void XFormView::resizeEvent(QResizeEvent *e)
+{
+ pts->setBoundingRect(rect());
+ ArthurFrame::resizeEvent(e);
+}
+
+void XFormView::paint(QPainter *p)
+{
+ p->save();
+ p->setRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::SmoothPixmapTransform);
+ switch (m_type) {
+ case VectorType:
+ drawVectorType(p);
+ break;
+ case PixmapType:
+ drawPixmapType(p);
+ break;
+ case TextType:
+ drawTextType(p);
+ break;
+ }
+ p->restore();
+}
+
+void XFormView::updateCtrlPoints(const QPolygonF &points)
+{
+ QPointF trans = points.at(0) - ctrlPoints.at(0);
+
+ if (qAbs(points.at(0).x() - points.at(1).x()) < 10
+ && qAbs(points.at(0).y() - points.at(1).y()) < 10)
+ pts->setPoints(ctrlPoints);
+ if (!trans.isNull()) {
+ ctrlPoints[0] = points.at(0);
+ ctrlPoints[1] += trans;
+ pts->setPoints(ctrlPoints);
+ }
+ ctrlPoints = points;
+
+ QLineF line(ctrlPoints.at(0), ctrlPoints.at(1));
+ m_rotation = line.angle(QLineF(0, 0, 1, 0));
+ if (line.dy() < 0)
+ m_rotation = 360 - m_rotation;
+
+ if (trans.isNull())
+ emit rotationChanged(int(m_rotation*10));
+}
+
+void XFormView::setVectorType()
+{
+ m_type = VectorType;
+ update();
+}
+
+void XFormView::setPixmapType()
+{
+ m_type = PixmapType;
+ update();
+}
+
+void XFormView::setTextType()
+{
+ m_type = TextType;
+ update();
+}
+
+void XFormView::setAnimation(bool animate)
+{
+ timer.stop();
+ if (animate)
+ timer.start(25, this);
+}
+
+void XFormView::changeRotation(int r)
+{
+ setRotation(qreal(r) / 10);
+}
+
+void XFormView::changeScale(int s)
+{
+ setScale(qreal(s) / 1000);
+}
+
+void XFormView::changeShear(int s)
+{
+ setShear(qreal(s) / 1000);
+}
+
+void XFormView::setShear(qreal s)
+{
+ m_shear = s;
+ update();
+}
+
+void XFormView::setScale(qreal s)
+{
+ m_scale = s;
+ update();
+}
+
+void XFormView::setRotation(qreal r)
+{
+ qreal old_rot = m_rotation;
+ m_rotation = r;
+
+ QPointF center(pts->points().at(0));
+ QMatrix m;
+ m.translate(center.x(), center.y());
+ m.rotate(m_rotation - old_rot);
+ m.translate(-center.x(), -center.y());
+ pts->setPoints(pts->points() * m);
+
+ update();
+}
+
+void XFormView::timerEvent(QTimerEvent *e)
+{
+ if (e->timerId() == timer.timerId()) {
+ QPointF center(pts->points().at(0));
+ QMatrix m;
+ m.translate(center.x(), center.y());
+ m.rotate(0.2);
+ m.translate(-center.x(), -center.y());
+ pts->setPoints(pts->points() * m);
+
+ setUpdatesEnabled(false);
+ static qreal scale_inc = 0.003;
+ static qreal shear_inc = -0.001;
+ emit scaleChanged(int((m_scale + scale_inc) * 1000));
+ emit shearChanged(int((m_shear + shear_inc) * 1000));
+ if (m_scale >= 4.0 || m_scale <= 0.1)
+ scale_inc = -scale_inc;
+ if (m_shear >= 1.0 || m_shear <= -1.0)
+ shear_inc = -shear_inc;
+ setUpdatesEnabled(true);
+
+ pts->firePointChange();
+ }
+}
+
+void XFormView::wheelEvent(QWheelEvent *e)
+{
+ m_scale += e->delta() / qreal(600);
+ m_scale = qMax(qreal(0.1), qMin(qreal(4), m_scale));
+ emit scaleChanged(int(m_scale*1000));
+}
+
+void XFormView::reset()
+{
+ emit rotationChanged(0);
+ emit scaleChanged(1000);
+ emit shearChanged(0);
+ ctrlPoints = QPolygonF();
+ ctrlPoints << QPointF(250, 250) << QPointF(350, 250);
+ pts->setPoints(ctrlPoints);
+ pts->firePointChange();
+}
+
+void XFormView::drawPixmapType(QPainter *painter)
+{
+ QPointF center(m_pixmap.width() / qreal(2), m_pixmap.height() / qreal(2));
+ painter->translate(ctrlPoints.at(0) - center);
+
+ painter->translate(center);
+ painter->rotate(m_rotation);
+ painter->scale(m_scale, m_scale);
+ painter->shear(0, m_shear);
+ painter->translate(-center);
+
+ painter->drawPixmap(QPointF(0, 0), m_pixmap);
+ painter->setPen(QPen(QColor(255, 0, 0, alpha), 0.25, Qt::SolidLine, Qt::FlatCap, Qt::BevelJoin));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRect(QRectF(0, 0, m_pixmap.width(), m_pixmap.height()).adjusted(-2, -2, 2, 2));
+}
+
+void XFormView::drawTextType(QPainter *painter)
+{
+ QPainterPath path;
+ QFont f("times new roman,utopia");
+ f.setStyleStrategy(QFont::ForceOutline);
+ f.setPointSize(72);
+ f.setStyleHint(QFont::Times);
+ path.addText(0, 0, f, m_text);
+
+ QFontMetrics fm(f);
+ QRectF br(fm.boundingRect(m_text));
+ QPointF center(br.center());
+ painter->translate(ctrlPoints.at(0) - center);
+
+ painter->translate(center);
+ painter->rotate(m_rotation);
+ painter->scale(m_scale, m_scale);
+ painter->shear(0, m_shear);
+ painter->translate(-center);
+
+ painter->fillPath(path, Qt::black);
+
+ painter->setPen(QPen(QColor(255, 0, 0, alpha), 0.25, Qt::SolidLine, Qt::FlatCap, Qt::BevelJoin));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRect(br.adjusted(-1, -1, 1, 1));
+}
+
+void XFormView::drawVectorType(QPainter *painter)
+{
+ QPainterPath path;
+ painter->translate(ctrlPoints.at(0) - QPointF(250,250));
+
+ painter->scale(0.77, 0.77);
+ painter->translate(98.9154 + 30 , -217.691 - 20);
+
+ QRect br(-55, 275, 500, 590);
+ QPoint center = br.center();
+ painter->translate(center.x(), center.y());
+ painter->rotate(m_rotation);
+ painter->scale(m_scale, m_scale);
+ painter->shear(0, m_shear);
+ painter->translate(-center.x(), -center.y());
+
+ painter->setPen(Qt::NoPen);
+ path.moveTo(120, 470);
+ path.lineTo(60+245, 470);
+ path.lineTo(60+245, 470+350);
+ path.lineTo(60, 470+350);
+ path.lineTo(60, 470+80);
+
+ painter->setBrush(Qt::white);
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor( 193, 193, 191, 255));
+ path.moveTo(329.336, 727.552);
+ path.cubicTo(QPointF(315.224, 726.328), QPointF(304.136, 715.816), QPointF(303.128, 694.936));
+ path.cubicTo(QPointF(306.368, 639.496), QPointF(309.608, 582.112), QPointF(271.232, 545.104));
+ path.cubicTo(QPointF(265.256, 499.024), QPointF(244.016, 482.104), QPointF(234.008, 452.512));
+ path.lineTo(218.24, 441.208);
+ path.lineTo(237.104, 411.688);
+ path.lineTo(245.168, 411.904);
+ path.lineTo(323.936, 571.168);
+ path.lineTo(340.424, 651.448);
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(136.232, 439.696);
+ path.cubicTo(QPointF(133.856, 455.248), QPointF(132.56, 470.512), QPointF(134.792, 485.272));
+ path.cubicTo(QPointF(118.376, 507.592), QPointF(105.92, 530.128), QPointF(104.48, 553.312));
+ path.cubicTo(QPointF(92.024, 586.504), QPointF(62.432, 614.584), QPointF(67.544, 680.104));
+ path.cubicTo(QPointF(84.176, 697.456), QPointF(107.432, 713.584), QPointF(127.376, 730.36));
+ path.cubicTo(QPointF(152.432, 751.312), QPointF(137.528, 778.96), QPointF(102.248, 772.408));
+ path.cubicTo(QPointF(94.4, 763.768), QPointF(76.616, 709.624), QPointF(42.92, 676.288));
+ path.lineTo(49.544, 632.584);
+ path.lineTo(81.368, 547.408);
+ path.lineTo(120.968, 484.048);
+ path.lineTo(125.36, 456.688);
+ path.lineTo(119.816, 386.776);
+ path.lineTo(124.424, 361.216);
+ path.lineTo(136.232, 439.696);
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(115.64, 341.416);
+ path.cubicTo(QPointF(116.576, 336.376), QPointF(117.8, 331.624), QPointF(119.312, 327.16));
+ path.lineTo(121.688, 342.784);
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(120.968, 500.464);
+ path.cubicTo(QPointF(108.368, 523.792), QPointF(103.976, 546.256), QPointF(132.92, 550.216));
+ path.cubicTo(QPointF(117.008, 553.888), QPointF(97.208, 568.648), QPointF(77.192, 593.488));
+ path.lineTo(77.624, 543.016);
+ path.lineTo(101.456, 503.272);
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(-33.256, 818.488);
+ path.cubicTo(QPointF(10.52, 838.144), QPointF(41.408, 837.064), QPointF(69.272, 850.96));
+ path.cubicTo(QPointF(91.304, 862.552), QPointF(113.552, 861.184), QPointF(126.944, 847.144));
+ path.cubicTo(QPointF(138.32, 832.456), QPointF(146.744, 831.736), QPointF(163.52, 830.224));
+ path.cubicTo(QPointF(190.952, 828.568), QPointF(217.736, 828.28), QPointF(241.928, 830.8));
+ path.lineTo(269.576, 833.032);
+ path.cubicTo(QPointF(269.072, 864.064), QPointF(328.04, 867.88), QPointF(345.392, 844.336));
+ path.cubicTo(QPointF(366.344, 819.424), QPointF(395.144, 808.264), QPointF(419.84, 790.192));
+ path.lineTo(289.304, 725.536);
+ path.cubicTo(QPointF(255.824, 806.464), QPointF(131.048, 827.632), QPointF(113.768, 763.264));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(286.424, 711.568);
+ path.cubicTo(QPointF(273.824, 711.496), QPointF(260.936, 715.6), QPointF(261.944, 732.16));
+ path.lineTo(266.192, 776.44);
+ path.lineTo(304.424, 756.64);
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(0, 0, 0, 255));
+ path.moveTo(-37.36, 821.224);
+ path.cubicTo(QPointF(7.136, 840.88), QPointF(38.6, 839.728), QPointF(66.968, 853.696));
+ path.cubicTo(QPointF(89.36, 865.216), QPointF(111.968, 863.92), QPointF(125.648, 849.808));
+ path.cubicTo(QPointF(137.24, 835.192), QPointF(145.808, 834.472), QPointF(162.872, 832.96));
+ path.cubicTo(QPointF(190.736, 831.232), QPointF(218.024, 831.016), QPointF(242.648, 833.464));
+ path.lineTo(270.728, 835.768);
+ path.cubicTo(QPointF(270.224, 866.8), QPointF(330.272, 870.544), QPointF(347.912, 847));
+ path.cubicTo(QPointF(369.224, 822.088), QPointF(398.528, 811), QPointF(423.656, 792.856));
+ path.lineTo(290.816, 728.272);
+ path.cubicTo(QPointF(256.76, 809.128), QPointF(129.824, 830.296), QPointF(112.256, 766));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(183, 114, 0, 255));
+ path.moveTo(382.328, 691.984);
+ path.cubicTo(QPointF(403.64, 698.968), QPointF(389.888, 720.28), QPointF(400.76, 732.52));
+ path.cubicTo(QPointF(405.44, 742.888), QPointF(415.304, 752.032), QPointF(431.792, 760.528));
+ path.cubicTo(QPointF(459.368, 774.424), QPointF(426.248, 799.336), QPointF(392.768, 812.08));
+ path.cubicTo(QPointF(351.944, 825.616), QPointF(344.024, 862.912), QPointF(299.312, 851.896));
+ path.cubicTo(QPointF(283.112, 846.496), QPointF(278.36, 831.808), QPointF(278.864, 809.128));
+ path.cubicTo(QPointF(284.264, 762.76), QPointF(277.784, 730.432), QPointF(278.792, 698.824));
+ path.cubicTo(QPointF(278.72, 686.152), QPointF(283.544, 684.64), QPointF(307.232, 687.952));
+ path.cubicTo(QPointF(310.04, 726.328), QPointF(352.376, 727.336), QPointF(382.328, 691.984));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(242, 183, 0, 255));
+ path.moveTo(339.632, 826.624);
+ path.cubicTo(QPointF(371.6, 814.312), QPointF(403.856, 798.112), QPointF(429.848, 782.128));
+ path.cubicTo(QPointF(437.84, 777.448), QPointF(438.92, 765.928), QPointF(427.688, 762.328));
+ path.cubicTo(QPointF(403.352, 748.504), QPointF(390.104, 731.224), QPointF(392.912, 708.76));
+ path.cubicTo(QPointF(393.344, 700.912), QPointF(383.696, 692.56), QPointF(381.104, 700.048));
+ path.cubicTo(QPointF(359.864, 771.472), QPointF(291.32, 767.656), QPointF(300.752, 696.952));
+ path.cubicTo(QPointF(301.256, 694.864), QPointF(301.76, 692.776), QPointF(302.264, 690.76));
+ path.cubicTo(QPointF(289.952, 688.24), QPointF(285.2, 690.976), QPointF(285.776, 700.408));
+ path.lineTo(295.28, 806.608);
+ path.cubicTo(QPointF(297.656, 830.8), QPointF(317.312, 836.128), QPointF(339.632, 826.624));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(0, 0, 0, 255));
+ path.moveTo(354.464, 537.544);
+ path.cubicTo(QPointF(379.16, 569.8), QPointF(404.432, 651.088), QPointF(384.416, 691.552));
+ path.cubicTo(QPointF(360.944, 737.776), QPointF(307.808, 743.248), QPointF(305.504, 695.8));
+ path.cubicTo(QPointF(308.816, 639.64), QPointF(311.984, 581.536), QPointF(273.68, 544.096));
+ path.cubicTo(QPointF(267.704, 497.368), QPointF(246.392, 480.232), QPointF(236.384, 450.28));
+ path.lineTo(203.12, 426.088);
+ path.lineTo(133.568, 435.088);
+ path.cubicTo(QPointF(130.76, 452.152), QPointF(129.104, 468.784), QPointF(131.552, 484.912));
+ path.cubicTo(QPointF(115.064, 507.376), QPointF(102.608, 530.056), QPointF(101.168, 553.312));
+ path.cubicTo(QPointF(88.712, 586.648), QPointF(59.12, 614.944), QPointF(64.232, 680.752));
+ path.cubicTo(QPointF(80.864, 698.248), QPointF(104.12, 714.448), QPointF(124.064, 731.296));
+ path.cubicTo(QPointF(149.12, 752.392), QPointF(135.512, 776.296), QPointF(100.232, 769.672));
+ path.cubicTo(QPointF(78.848, 746.056), QPointF(56.744, 722.872), QPointF(35.288, 699.328));
+ path.cubicTo(QPointF(12.392, 683.056), QPointF(3.896, 662.176), QPointF(27.368, 630.496));
+ path.cubicTo(QPointF(43.424, 609.04), QPointF(47.96, 562.456), QPointF(62, 543.664));
+ path.cubicTo(QPointF(74.312, 525.16), QPointF(92.24, 508.6), QPointF(105.272, 490.096));
+ path.cubicTo(QPointF(112.184, 477.928), QPointF(114.344, 468.568), QPointF(113.264, 454.456));
+ path.lineTo(110.312, 369.136);
+ path.cubicTo(QPointF(108.368, 307.216), QPointF(142.424, 274.24), QPointF(189.8, 275.248));
+ path.cubicTo(QPointF(243.512, 275.752), QPointF(287.576, 312.472), QPointF(288.152, 378.28));
+ path.cubicTo(QPointF(292.688, 410.32), QPointF(283.256, 428.68), QPointF(308.672, 474.472));
+ path.cubicTo(QPointF(334.52, 522.712), QPointF(338.552, 520.12), QPointF(354.464, 537.544));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(261.296, 503.632);
+ path.lineTo(263.528, 512.2);
+ path.cubicTo(QPointF(257.696, 501.688), QPointF(250.712, 483.616), QPointF(241.928, 475.696));
+ path.cubicTo(QPointF(239.264, 473.536), QPointF(235.808, 473.608), QPointF(233.72, 475.624));
+ path.cubicTo(QPointF(222.056, 486.928), QPointF(193.112, 510.112), QPointF(169.928, 507.088));
+ path.cubicTo(QPointF(152.072, 505.288), QPointF(134.648, 493.264), QPointF(130.832, 480.232));
+ path.cubicTo(QPointF(128.816, 470.872), QPointF(129.752, 463.168), QPointF(130.976, 455.32));
+ path.lineTo(240.704, 453.52);
+ path.cubicTo(QPointF(238.472, 463.168), QPointF(253.088, 487), QPointF(261.296, 503.632));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(143.144, 363.232);
+ path.cubicTo(QPointF(154.088, 363.232), QPointF(163.88, 376.84), QPointF(163.808, 395.632));
+ path.cubicTo(QPointF(163.736, 408.232), QPointF(155.528, 411.472), QPointF(149.336, 417.016));
+ path.cubicTo(QPointF(146.6, 419.536), QPointF(145.952, 433.144), QPointF(142.568, 433.144));
+ path.cubicTo(QPointF(131.696, 433.144), QPointF(123.488, 413.776), QPointF(123.488, 395.632));
+ path.cubicTo(QPointF(123.488, 377.56), QPointF(132.272, 363.232), QPointF(143.144, 363.232));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(255, 255, 255, 255));
+ path.moveTo(144.368, 375.04);
+ path.cubicTo(QPointF(154.088, 375.04), QPointF(160.856, 379.936), QPointF(161.648, 391.312));
+ path.cubicTo(QPointF(162.224, 399.16), QPointF(160.136, 411.76), QPointF(154.664, 414.424));
+ path.cubicTo(QPointF(152.144, 415.648), QPointF(143.432, 426.664), QPointF(140.408, 426.52));
+ path.cubicTo(QPointF(128.096, 425.944), QPointF(125, 402.112), QPointF(125.936, 390.736));
+ path.cubicTo(QPointF(126.8, 379.36), QPointF(134.72, 375.04), QPointF(144.368, 375.04));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(0, 0, 0, 255));
+ path.moveTo(141.848, 382.672);
+ path.cubicTo(QPointF(148.544, 382.096), QPointF(154.736, 389.728), QPointF(155.6, 399.664));
+ path.cubicTo(QPointF(156.464, 409.6), QPointF(151.64, 418.24), QPointF(144.944, 418.816));
+ path.cubicTo(QPointF(138.248, 419.392), QPointF(132.056, 411.76), QPointF(131.192, 401.752));
+ path.cubicTo(QPointF(130.328, 391.816), QPointF(135.152, 383.248), QPointF(141.848, 382.672));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(151.064, 397.288);
+ path.cubicTo(QPointF(151.424, 399.088), QPointF(149.408, 400.024), QPointF(148.832, 398.224));
+ path.cubicTo(QPointF(148.256, 395.992), QPointF(146.888, 393.328), QPointF(145.088, 391.168));
+ path.cubicTo(QPointF(143.936, 389.872), QPointF(145.088, 388.432), QPointF(146.528, 389.44));
+ path.cubicTo(QPointF(149.048, 391.528), QPointF(150.488, 394.12), QPointF(151.064, 397.288));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(216.944, 360.712);
+ path.cubicTo(QPointF(232.712, 360.712), QPointF(245.6, 377.416), QPointF(245.6, 397.792));
+ path.cubicTo(QPointF(245.6, 418.24), QPointF(232.712, 434.872), QPointF(216.944, 434.872));
+ path.cubicTo(QPointF(201.176, 434.872), QPointF(188.432, 418.24), QPointF(188.432, 397.792));
+ path.cubicTo(QPointF(188.432, 377.416), QPointF(201.176, 360.712), QPointF(216.944, 360.712));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(255, 255, 255, 255));
+ path.moveTo(224.792, 374.968);
+ path.cubicTo(QPointF(235.664, 378.856), QPointF(241.928, 387.424), QPointF(242.72, 396.568));
+ path.cubicTo(QPointF(243.656, 407.08), QPointF(239.408, 418.96), QPointF(230.264, 425.944));
+ path.cubicTo(QPointF(227.672, 427.888), QPointF(197.72, 416.08), QPointF(195.992, 411.616));
+ path.cubicTo(QPointF(193.4, 405.208), QPointF(191.816, 392.896), QPointF(193.76, 385.624));
+ path.cubicTo(QPointF(194.552, 382.744), QPointF(197.216, 378.568), QPointF(201.176, 376.336));
+ path.cubicTo(QPointF(207.44, 372.808), QPointF(216.656, 372.088), QPointF(224.792, 374.968));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(0, 0, 0, 255));
+ path.moveTo(216.872, 380.944);
+ path.cubicTo(QPointF(225.584, 380.944), QPointF(232.712, 389.296), QPointF(232.712, 399.448));
+ path.cubicTo(QPointF(232.712, 409.672), QPointF(225.584, 418.024), QPointF(216.872, 418.024));
+ path.cubicTo(QPointF(208.16, 418.024), QPointF(201.032, 409.672), QPointF(201.032, 399.448));
+ path.cubicTo(QPointF(201.032, 389.296), QPointF(208.16, 380.944), QPointF(216.872, 380.944));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(227.096, 392.392);
+ path.cubicTo(QPointF(228.104, 394.048), QPointF(226.448, 395.776), QPointF(225.224, 394.12));
+ path.cubicTo(QPointF(223.784, 392.104), QPointF(221.408, 389.944), QPointF(218.888, 388.432));
+ path.cubicTo(QPointF(217.232, 387.568), QPointF(217.808, 385.624), QPointF(219.68, 386.2));
+ path.cubicTo(QPointF(222.92, 387.28), QPointF(225.368, 389.368), QPointF(227.096, 392.392));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(183, 114, 0, 255));
+ path.moveTo(164.96, 404.488);
+ path.cubicTo(QPointF(172.376, 402.328), QPointF(184.112, 403.048), QPointF(192.248, 404.632));
+ path.cubicTo(QPointF(200.384, 406.792), QPointF(222.056, 418.24), QPointF(245.024, 430.696));
+ path.cubicTo(QPointF(247.976, 432.208), QPointF(248.84, 437.104), QPointF(245.024, 438.688));
+ path.cubicTo(QPointF(239.12, 439.12), QPointF(249.272, 453.664), QPointF(238.904, 458.848));
+ path.cubicTo(QPointF(223.352, 462.88), QPointF(198.44, 485.992), QPointF(186.128, 487.864));
+ path.cubicTo(QPointF(179.288, 489.376), QPointF(172.232, 489.592), QPointF(164.6, 487.864));
+ path.cubicTo(QPointF(140.552, 482.968), QPointF(134.216, 455.608), QPointF(122.912, 450.064));
+ path.cubicTo(QPointF(119.816, 446.824), QPointF(121.4, 441.208), QPointF(122.408, 440.056));
+ path.cubicTo(QPointF(123.632, 434.224), QPointF(149.696, 406.216), QPointF(164.96, 404.488));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(242, 183, 0, 255));
+ path.moveTo(185.408, 405.856);
+ path.cubicTo(QPointF(198.44, 407.296), QPointF(226.088, 423.928), QPointF(239.408, 430.624));
+ path.cubicTo(QPointF(242.72, 432.424), QPointF(242.504, 437.824), QPointF(239.552, 438.688));
+ path.cubicTo(QPointF(236.384, 440.488), QPointF(235.448, 438.256), QPointF(232.928, 437.896));
+ path.cubicTo(QPointF(228.896, 435.736), QPointF(222.272, 440.92), QPointF(217.016, 444.88));
+ path.cubicTo(QPointF(186.704, 467.776), QPointF(180.656, 465.256), QPointF(156.176, 462.664));
+ path.cubicTo(QPointF(147.68, 460.576), QPointF(142.136, 457.984), QPointF(139.688, 455.968));
+ path.cubicTo(QPointF(141.488, 445.888), QPointF(160.496, 407.656), QPointF(166.76, 406.792));
+ path.cubicTo(QPointF(168.344, 404.704), QPointF(179.936, 404.632), QPointF(185.408, 405.856));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(183, 114, 0, 255));
+ path.moveTo(190.664, 412.048);
+ path.lineTo(193.76, 413.416);
+ path.cubicTo(QPointF(196.064, 414.712), QPointF(193.256, 418.168), QPointF(190.736, 417.088));
+ path.lineTo(186.2, 415.504);
+ path.cubicTo(QPointF(183.536, 413.272), QPointF(186.704, 410.104), QPointF(190.664, 412.048));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(268.568, 452.368);
+ path.cubicTo(QPointF(273.032, 454.384), QPointF(279.224, 457.192), QPointF(282.536, 460.144));
+ path.cubicTo(QPointF(285.488, 464.104), QPointF(286.784, 468.064), QPointF(286.424, 472.024));
+ path.cubicTo(QPointF(285.776, 474.544), QPointF(284.12, 476.344), QPointF(281.24, 477.424));
+ path.cubicTo(QPointF(277.856, 478.216), QPointF(273.68, 477.424), QPointF(271.376, 474.112));
+ path.cubicTo(QPointF(269.864, 471.448), QPointF(265.256, 462.16), QPointF(263.96, 460.576));
+ path.cubicTo(QPointF(262.232, 457.12), QPointF(261.944, 454.456), QPointF(262.88, 452.368));
+ path.cubicTo(QPointF(264.032, 451.288), QPointF(266.048, 451), QPointF(268.568, 452.368));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(255, 255, 255, 255));
+ path.moveTo(273.752, 461.584);
+ path.cubicTo(QPointF(275.48, 462.376), QPointF(277.928, 463.456), QPointF(279.224, 464.68));
+ path.cubicTo(QPointF(280.376, 466.264), QPointF(280.88, 467.776), QPointF(280.736, 469.36));
+ path.cubicTo(QPointF(280.52, 470.296), QPointF(279.8, 471.016), QPointF(278.72, 471.448));
+ path.cubicTo(QPointF(277.352, 471.808), QPointF(275.768, 471.448), QPointF(274.832, 470.152));
+ path.cubicTo(QPointF(274.256, 469.144), QPointF(272.456, 465.472), QPointF(271.952, 464.824));
+ path.cubicTo(QPointF(271.232, 463.456), QPointF(271.088, 462.448), QPointF(271.448, 461.584));
+ path.cubicTo(QPointF(271.952, 461.152), QPointF(272.744, 461.08), QPointF(273.752, 461.584));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(238.616, 358.552);
+ path.cubicTo(QPointF(239.048, 359.2), QPointF(238.976, 359.776), QPointF(238.4, 360.28));
+ path.cubicTo(QPointF(237.896, 360.784), QPointF(237.176, 360.712), QPointF(236.24, 360.208));
+ path.lineTo(231.632, 356.248);
+ path.cubicTo(QPointF(231.056, 355.744), QPointF(230.912, 354.952), QPointF(231.272, 354.088));
+ path.cubicTo(QPointF(232.28, 353.44), QPointF(233.144, 353.44), QPointF(233.936, 354.088));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(235.592, 305.992);
+ path.cubicTo(QPointF(239.624, 308.224), QPointF(240.848, 313.912), QPointF(238.184, 318.592));
+ path.cubicTo(QPointF(235.592, 323.2), QPointF(230.12, 325.144), QPointF(226.016, 322.84));
+ path.cubicTo(QPointF(221.984, 320.536), QPointF(220.76, 314.92), QPointF(223.424, 310.24));
+ path.cubicTo(QPointF(226.016, 305.56), QPointF(231.488, 303.688), QPointF(235.592, 305.992));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(374.912, 680.536);
+ path.cubicTo(QPointF(378.296, 683.128), QPointF(373.256, 687.376), QPointF(371.024, 686.296));
+ path.cubicTo(QPointF(369.152, 685.648), QPointF(367.784, 683.488), QPointF(366.92, 682.408));
+ path.cubicTo(QPointF(366.128, 681.184), QPointF(366.2, 679.168), QPointF(366.92, 678.448));
+ path.cubicTo(QPointF(367.712, 677.44), QPointF(369.728, 677.656), QPointF(371.024, 678.52));
+ path.cubicTo(QPointF(372.32, 679.168), QPointF(373.616, 679.888), QPointF(374.912, 680.536));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(297.44, 551.512);
+ path.cubicTo(QPointF(338.984, 572.896), QPointF(350, 611.56), QPointF(332.072, 664.192));
+ path.cubicTo(QPointF(330.992, 666.64), QPointF(334.16, 668.368), QPointF(335.24, 666.064));
+ path.cubicTo(QPointF(354.824, 610.336), QPointF(341.432, 571.312), QPointF(299.024, 548.56));
+ path.cubicTo(QPointF(296.864, 547.552), QPointF(295.28, 550.432), QPointF(297.44, 551.512));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(72.008, 569.512);
+ path.cubicTo(QPointF(38.312, 627.256), QPointF(38.096, 662.68), QPointF(62.504, 681.328));
+ path.cubicTo(QPointF(63.728, 682.264), QPointF(64.448, 680.032), QPointF(63.296, 679.168));
+ path.cubicTo(QPointF(36.296, 655.48), QPointF(48.896, 615.52), QPointF(74.168, 570.88));
+ path.cubicTo(QPointF(74.888, 569.584), QPointF(72.512, 568.432), QPointF(72.008, 569.512));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(289.376, 586.864);
+ path.cubicTo(QPointF(289.232, 589.168), QPointF(288.368, 589.528), QPointF(286.424, 587.368));
+ path.cubicTo(QPointF(279.8, 575.848), QPointF(235.088, 551.44), QPointF(213.344, 548.704));
+ path.cubicTo(QPointF(209.24, 547.264), QPointF(209.456, 545.392), QPointF(213.488, 544.816));
+ path.cubicTo(QPointF(229.184, 544.816), QPointF(241.28, 537.904), QPointF(254.96, 537.904));
+ path.cubicTo(QPointF(258.704, 538.048), QPointF(262.304, 539.488), QPointF(264.392, 541.648));
+ path.cubicTo(QPointF(269.504, 544.96), QPointF(288.08, 570.592), QPointF(289.376, 586.864));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(180.152, 546.832);
+ path.cubicTo(QPointF(180.872, 550.792), QPointF(163.808, 545.68), QPointF(164.744, 556.696));
+ path.cubicTo(QPointF(165.032, 559.72), QPointF(160.496, 561.376), QPointF(160.64, 556.696));
+ path.cubicTo(QPointF(160.64, 548.272), QPointF(161.072, 548.416), QPointF(152.72, 546.832));
+ path.cubicTo(QPointF(151.208, 546.76), QPointF(151.352, 544.528), QPointF(152.72, 544.816));
+ path.lineTo(152.72, 544.816);
+ path.cubicTo(QPointF(158.696, 546.472), QPointF(166.76, 542.872), QPointF(166.4, 538.84));
+ path.cubicTo(QPointF(166.256, 537.472), QPointF(168.56, 537.688), QPointF(168.488, 538.84));
+ path.cubicTo(QPointF(167.984, 545.248), QPointF(181.664, 542.152), QPointF(180.152, 546.832));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(193, 193, 191, 255));
+ path.moveTo(151.568, 705.376);
+ path.cubicTo(QPointF(151.64, 708.328), QPointF(148.76, 707.68), QPointF(148.544, 705.592));
+ path.cubicTo(QPointF(140.192, 680.536), QPointF(143.72, 618.832), QPointF(151.856, 598.96));
+ path.cubicTo(QPointF(152.432, 596.08), QPointF(156.248, 596.944), QPointF(155.744, 598.96));
+ path.cubicTo(QPointF(147.104, 635.464), QPointF(147.248, 673.048), QPointF(151.568, 705.376));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(183, 114, 0, 255));
+ path.moveTo(51.704, 684.424);
+ path.cubicTo(QPointF(75.68, 707.824), QPointF(91.376, 743.248), QPointF(114.632, 775.288));
+ path.cubicTo(QPointF(148.472, 816.04), QPointF(121.472, 858.304), QPointF(66.464, 845.56));
+ path.cubicTo(QPointF(38.888, 835.192), QPointF(-0.784, 836.344), QPointF(-32.68, 825.832));
+ path.cubicTo(QPointF(-55.072, 820.36), QPointF(-55.864, 809.272), QPointF(-44.416, 787.6));
+ path.cubicTo(QPointF(-40.384, 773.776), QPointF(-40.024, 751.312), QPointF(-43.768, 732.592));
+ path.cubicTo(QPointF(-45.784, 718.408), QPointF(-39.232, 710.488), QPointF(-24.112, 708.832));
+ path.lineTo(-24.112, 708.832);
+ path.cubicTo(QPointF(-11.296, 708.688), QPointF(6.56, 713.872), QPointF(16.28, 686.44));
+ path.cubicTo(QPointF(23.552, 673.336), QPointF(40.976, 672.976), QPointF(51.704, 684.424));
+ path.closeSubpath();
+ painter->drawPath(path);
+ path = QPainterPath();
+
+ painter->setBrush(QColor(242, 183, 0, 255));
+ path.moveTo(24.632, 699.04);
+ path.cubicTo(QPointF(23.84, 680.968), QPointF(39.32, 677.296), QPointF(49.688, 688.312));
+ path.cubicTo(QPointF(68.192, 710.992), QPointF(85.112, 736.048), QPointF(100.376, 764.992));
+ path.cubicTo(QPointF(124.712, 804.16), QPointF(104.624, 842.68), QPointF(67.904, 828.064));
+ path.cubicTo(QPointF(49.688, 817.84), QPointF(6.128, 813.304), QPointF(-17.344, 809.128));
+ path.cubicTo(QPointF(-33.04, 807.832), QPointF(-35.128, 797.608), QPointF(-29.152, 791.848));
+ path.cubicTo(QPointF(-20.944, 782.416), QPointF(-20.08, 759.808), QPointF(-27.856, 740.512));
+ path.cubicTo(QPointF(-35.56, 728.56), QPointF(-21.088, 715.384), QPointF(-9.712, 720.856));
+ path.cubicTo(QPointF(0.8, 727.048), QPointF(25.64, 713.08), QPointF(24.632, 699.04));
+ path.closeSubpath();
+ painter->drawPath(path);
+
+ painter->setPen(QPen(QColor(255, 0, 0, alpha), 0.25, Qt::SolidLine, Qt::FlatCap, Qt::BevelJoin));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRect(br.adjusted(-1, -1, 1, 1));
+}
+
+
+XFormWidget::XFormWidget(QWidget *parent)
+ : QWidget(parent), textEditor(new QLineEdit)
+{
+ setWindowTitle(tr("Affine Transformations"));
+
+ view = new XFormView(this);
+ view->setMinimumSize(200, 200);
+
+ QGroupBox *mainGroup = new QGroupBox(this);
+ mainGroup->setFixedWidth(180);
+ mainGroup->setTitle(tr("Affine Transformations"));
+
+ QGroupBox *rotateGroup = new QGroupBox(mainGroup);
+ rotateGroup->setTitle(tr("Rotate"));
+ QSlider *rotateSlider = new QSlider(Qt::Horizontal, rotateGroup);
+ rotateSlider->setRange(0, 3600);
+ rotateSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ QGroupBox *scaleGroup = new QGroupBox(mainGroup);
+ scaleGroup->setTitle(tr("Scale"));
+ QSlider *scaleSlider = new QSlider(Qt::Horizontal, scaleGroup);
+ scaleSlider->setRange(1, 4000);
+ scaleSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ QGroupBox *shearGroup = new QGroupBox(mainGroup);
+ shearGroup->setTitle(tr("Shear"));
+ QSlider *shearSlider = new QSlider(Qt::Horizontal, shearGroup);
+ shearSlider->setRange(-990, 990);
+ shearSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ QGroupBox *typeGroup = new QGroupBox(mainGroup);
+ typeGroup->setTitle(tr("Type"));
+ QRadioButton *vectorType = new QRadioButton(typeGroup);
+ QRadioButton *pixmapType = new QRadioButton(typeGroup);
+ QRadioButton *textType= new QRadioButton(typeGroup);
+ vectorType->setText(tr("Vector Image"));
+ pixmapType->setText(tr("Pixmap"));
+ textType->setText(tr("Text"));
+
+ QPushButton *resetButton = new QPushButton(mainGroup);
+ resetButton->setText(tr("Reset Transform"));
+
+ QPushButton *animateButton = new QPushButton(mainGroup);
+ animateButton->setText(tr("Animate"));
+ animateButton->setCheckable(true);
+
+ QPushButton *showSourceButton = new QPushButton(mainGroup);
+ showSourceButton->setText(tr("Show Source"));
+#ifdef QT_OPENGL_SUPPORT
+ QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
+ enableOpenGLButton->setText(tr("Use OpenGL"));
+ enableOpenGLButton->setCheckable(true);
+ enableOpenGLButton->setChecked(view->usesOpenGL());
+ if (!QGLFormat::hasOpenGL())
+ enableOpenGLButton->hide();
+#endif
+ QPushButton *whatsThisButton = new QPushButton(mainGroup);
+ whatsThisButton->setText(tr("What's This?"));
+ whatsThisButton->setCheckable(true);
+
+ QHBoxLayout *viewLayout = new QHBoxLayout(this);
+ viewLayout->addWidget(view);
+ viewLayout->addWidget(mainGroup);
+
+ QVBoxLayout *rotateGroupLayout = new QVBoxLayout(rotateGroup);
+ rotateGroupLayout->addWidget(rotateSlider);
+
+ QVBoxLayout *scaleGroupLayout = new QVBoxLayout(scaleGroup);
+ scaleGroupLayout->addWidget(scaleSlider);
+
+ QVBoxLayout *shearGroupLayout = new QVBoxLayout(shearGroup);
+ shearGroupLayout->addWidget(shearSlider);
+
+ QVBoxLayout *typeGroupLayout = new QVBoxLayout(typeGroup);
+ typeGroupLayout->addWidget(vectorType);
+ typeGroupLayout->addWidget(pixmapType);
+ typeGroupLayout->addWidget(textType);
+ typeGroupLayout->addSpacing(4);
+ typeGroupLayout->addWidget(textEditor);
+
+ QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
+ mainGroupLayout->addWidget(rotateGroup);
+ mainGroupLayout->addWidget(scaleGroup);
+ mainGroupLayout->addWidget(shearGroup);
+ mainGroupLayout->addWidget(typeGroup);
+ mainGroupLayout->addStretch(1);
+ mainGroupLayout->addWidget(resetButton);
+ mainGroupLayout->addWidget(animateButton);
+ mainGroupLayout->addWidget(showSourceButton);
+#ifdef QT_OPENGL_SUPPORT
+ mainGroupLayout->addWidget(enableOpenGLButton);
+#endif
+ mainGroupLayout->addWidget(whatsThisButton);
+
+ connect(rotateSlider, SIGNAL(valueChanged(int)), view, SLOT(changeRotation(int)));
+ connect(shearSlider, SIGNAL(valueChanged(int)), view, SLOT(changeShear(int)));
+ connect(scaleSlider, SIGNAL(valueChanged(int)), view, SLOT(changeScale(int)));
+
+ connect(vectorType, SIGNAL(clicked()), view, SLOT(setVectorType()));
+ connect(pixmapType, SIGNAL(clicked()), view, SLOT(setPixmapType()));
+ connect(textType, SIGNAL(clicked()), view, SLOT(setTextType()));
+ connect(textType, SIGNAL(toggled(bool)), textEditor, SLOT(setEnabled(bool)));
+ connect(textEditor, SIGNAL(textChanged(QString)), view, SLOT(setText(QString)));
+
+ connect(view, SIGNAL(rotationChanged(int)), rotateSlider, SLOT(setValue(int)));
+ connect(view, SIGNAL(scaleChanged(int)), scaleSlider, SLOT(setValue(int)));
+ connect(view, SIGNAL(shearChanged(int)), shearSlider, SLOT(setValue(int)));
+
+ connect(resetButton, SIGNAL(clicked()), view, SLOT(reset()));
+ connect(animateButton, SIGNAL(clicked(bool)), view, SLOT(setAnimation(bool)));
+ connect(whatsThisButton, SIGNAL(clicked(bool)), view, SLOT(setDescriptionEnabled(bool)));
+ connect(whatsThisButton, SIGNAL(clicked(bool)), view->hoverPoints(), SLOT(setDisabled(bool)));
+ connect(view, SIGNAL(descriptionEnabledChanged(bool)), view->hoverPoints(), SLOT(setDisabled(bool)));
+ connect(view, SIGNAL(descriptionEnabledChanged(bool)), whatsThisButton, SLOT(setChecked(bool)));
+ connect(showSourceButton, SIGNAL(clicked()), view, SLOT(showSource()));
+#ifdef QT_OPENGL_SUPPORT
+ connect(enableOpenGLButton, SIGNAL(clicked(bool)), view, SLOT(enableOpenGL(bool)));
+#endif
+ view->loadSourceFile(":res/affine/xform.cpp");
+ view->loadDescription(":res/affine/xform.html");
+
+ // defaults
+ view->reset();
+ vectorType->setChecked(true);
+ textEditor->setText("Qt Software");
+ textEditor->setEnabled(false);
+
+ animateButton->animateClick();
+}
diff --git a/demos/affine/xform.h b/demos/affine/xform.h
new file mode 100644
index 0000000..f33e63d
--- /dev/null
+++ b/demos/affine/xform.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef XFORM_H
+#define XFORM_H
+
+#include "arthurwidgets.h"
+
+#include <QBasicTimer>
+#include <QPolygonF>
+
+class HoverPoints;
+QT_FORWARD_DECLARE_CLASS(QLineEdit)
+
+class XFormView : public ArthurFrame
+{
+public:
+ Q_OBJECT
+
+ Q_PROPERTY(XFormType type READ type WRITE setType)
+ Q_PROPERTY(bool animation READ animation WRITE setAnimation)
+ Q_PROPERTY(qreal shear READ shear WRITE setShear)
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation)
+ Q_PROPERTY(qreal scale READ scale WRITE setScale)
+ Q_PROPERTY(QString text READ text WRITE setText)
+ Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap)
+ Q_ENUMS(XFormType)
+
+public:
+ enum XFormType { VectorType, PixmapType, TextType };
+
+ XFormView(QWidget *parent);
+ void paint(QPainter *);
+ void drawVectorType(QPainter *painter);
+ void drawPixmapType(QPainter *painter);
+ void drawTextType(QPainter *painter);
+ QSize sizeHint() const { return QSize(500, 500); }
+
+ void mousePressEvent(QMouseEvent *e);
+ void resizeEvent(QResizeEvent *e);
+ HoverPoints *hoverPoints() { return pts; }
+
+ bool animation() const { return timer.isActive(); }
+ qreal shear() const { return m_shear; }
+ qreal scale() const { return m_scale; }
+ qreal rotation() const { return m_rotation; }
+ void setShear(qreal s);
+ void setScale(qreal s);
+ void setRotation(qreal r);
+
+ XFormType type() const;
+ QPixmap pixmap() const;
+ QString text() const;
+
+public slots:
+ void setAnimation(bool animate);
+ void updateCtrlPoints(const QPolygonF &);
+ void changeRotation(int rotation);
+ void changeScale(int scale);
+ void changeShear(int shear);
+
+ void setText(const QString &);
+ void setPixmap(const QPixmap &);
+ void setType(XFormType t);
+
+ void setVectorType();
+ void setPixmapType();
+ void setTextType();
+ void reset();
+
+signals:
+ void rotationChanged(int rotation);
+ void scaleChanged(int scale);
+ void shearChanged(int shear);
+
+protected:
+ void timerEvent(QTimerEvent *e);
+ void wheelEvent(QWheelEvent *);
+
+private:
+ QPolygonF ctrlPoints;
+ HoverPoints *pts;
+ qreal m_rotation;
+ qreal m_scale;
+ qreal m_shear;
+ XFormType m_type;
+ QPixmap m_pixmap;
+ QString m_text;
+ QBasicTimer timer;
+};
+
+class XFormWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ XFormWidget(QWidget *parent);
+
+private:
+ XFormView *view;
+ QLineEdit *textEditor;
+};
+
+#endif // XFORM_H
diff --git a/demos/affine/xform.html b/demos/affine/xform.html
new file mode 100644
index 0000000..17325ac
--- /dev/null
+++ b/demos/affine/xform.html
@@ -0,0 +1,23 @@
+<html>
+<center>
+<h2>Affine Transformations</h2>
+</center>
+
+<p>In this demo we demonstrate Qt's ability to perform affine transformations
+on painting operations.</p>
+
+<p>Transformations can be performed on any kind of graphics drawn using
+QPainter. The transformations used to display the vector graphics, images,
+and text can be adjusted in the following ways:</p>
+
+<ul>
+ <li>Dragging the red circle in the centre of each drawing moves it to a new
+ position.</li>
+ <li>Dragging the displaced red circle causes the current drawing to be
+ rotated about the central circle. Rotation can also be controlled with
+ the <b>Rotate</b> slider.</li>
+ <li>Scaling is controlled with the <b>Scale</b> slider.</li>
+ <li>Each drawing can be sheared with the <b>Shear</b> slider.</li>
+</ul>
+
+</html>
diff --git a/demos/arthurplugin/arthur_plugin.qrc b/demos/arthurplugin/arthur_plugin.qrc
new file mode 100644
index 0000000..e5170e6
--- /dev/null
+++ b/demos/arthurplugin/arthur_plugin.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/trolltech/arthurplugin">
+ <file>bg1.jpg</file>
+ <file>flower.jpg</file>
+ <file>flower_alpha.jpg</file>
+</qresource>
+</RCC>
diff --git a/demos/arthurplugin/arthurplugin.pro b/demos/arthurplugin/arthurplugin.pro
new file mode 100644
index 0000000..d4827a1
--- /dev/null
+++ b/demos/arthurplugin/arthurplugin.pro
@@ -0,0 +1,53 @@
+
+QTDIR = $$QT_SOURCE_TREE
+
+CONFIG += designer plugin
+TEMPLATE = lib
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/designer
+
+contains(QT_CONFIG, opengl) {
+ DEFINES += QT_OPENGL_SUPPORT
+ QT += opengl
+}
+
+SHARED_FOLDER = ../shared
+include(../shared/shared.pri)
+
+DEMO_DEFORM_DIR = ../deform
+DEMO_AFFINE_DIR = ../affine
+DEMO_GRADIENT_DIR = ../gradients
+DEMO_STROKE_DIR = ../pathstroke
+DEMO_COMPOSITION_DIR = ../composition
+
+INCLUDEPATH += $$DEMO_DEFORM_DIR $$DEMO_AFFINE_DIR $$DEMO_GRADIENT_DIR $$DEMO_STROKE_DIR $$DEMO_COMPOSITION_DIR
+
+SOURCES = plugin.cpp \
+ $$DEMO_COMPOSITION_DIR/composition.cpp \
+ $$DEMO_AFFINE_DIR/xform.cpp \
+ $$DEMO_DEFORM_DIR/pathdeform.cpp \
+ $$DEMO_GRADIENT_DIR/gradients.cpp \
+ $$DEMO_STROKE_DIR/pathstroke.cpp \
+
+
+HEADERS = \
+ $$DEMO_COMPOSITION_DIR/composition.h \
+ $$DEMO_AFFINE_DIR/xform.h \
+ $$DEMO_DEFORM_DIR/pathdeform.h \
+ $$DEMO_GRADIENT_DIR/gradients.h \
+ $$DEMO_STROKE_DIR/pathstroke.h \
+
+RESOURCES += arthur_plugin.qrc
+
+# install
+target.path = $$[QT_INSTALL_PLUGINS]/designer
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.jpg *.png
+sources.path = $$[QT_INSTALL_DEMOS]/arthurplugin
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
+win32-msvc* {
+ QMAKE_CFLAGS += /Zm500
+ QMAKE_CXXFLAGS += /Zm500
+}
+
diff --git a/demos/arthurplugin/bg1.jpg b/demos/arthurplugin/bg1.jpg
new file mode 100644
index 0000000..dfc7cee
--- /dev/null
+++ b/demos/arthurplugin/bg1.jpg
Binary files differ
diff --git a/demos/arthurplugin/flower.jpg b/demos/arthurplugin/flower.jpg
new file mode 100644
index 0000000..f8e022c
--- /dev/null
+++ b/demos/arthurplugin/flower.jpg
Binary files differ
diff --git a/demos/arthurplugin/flower_alpha.jpg b/demos/arthurplugin/flower_alpha.jpg
new file mode 100644
index 0000000..6a3c2a0
--- /dev/null
+++ b/demos/arthurplugin/flower_alpha.jpg
Binary files differ
diff --git a/demos/arthurplugin/plugin.cpp b/demos/arthurplugin/plugin.cpp
new file mode 100644
index 0000000..e2bf54e
--- /dev/null
+++ b/demos/arthurplugin/plugin.cpp
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtDesigner/QDesignerContainerExtension>
+#include <QtDesigner/QDesignerCustomWidgetInterface>
+
+#include <QtCore/qplugin.h>
+#include <QtGui/QIcon>
+#include <QtGui/QPixmap>
+
+#include "xform.h"
+#include "pathdeform.h"
+#include "gradients.h"
+#include "pathstroke.h"
+#include "hoverpoints.h"
+#include "composition.h"
+
+QT_FORWARD_DECLARE_CLASS(QDesignerFormEditorInterface)
+
+static inline QString customWidgetDomXml(const QString &className)
+{
+ QString rc = QLatin1String("<ui language=\"c++\"><widget class=\"");
+ rc += className;
+ rc += QLatin1String("\" name=\"");
+ QString objectName = className;
+ objectName[0] = objectName.at(0).toLower();
+ rc += objectName;
+ rc += QLatin1String("\"/></ui>");
+ return rc;
+}
+
+class PathDeformRendererEx : public PathDeformRenderer
+{
+ Q_OBJECT
+public:
+ PathDeformRendererEx(QWidget *parent) : PathDeformRenderer(parent) { }
+ QSize sizeHint() const { return QSize(300, 200); }
+};
+
+class DemoPlugin : public QDesignerCustomWidgetInterface
+{
+ Q_INTERFACES(QDesignerCustomWidgetInterface)
+
+protected:
+ DemoPlugin(const QString &className);
+
+public:
+ QString name() const { return m_className; }
+ bool isContainer() const { return false; }
+ bool isInitialized() const { return m_initialized; }
+ QIcon icon() const { return QIcon(); }
+ QString codeTemplate() const { return QString(); }
+ QString whatsThis() const { return QString(); }
+ QString toolTip() const { return QString(); }
+ QString group() const { return "Arthur Widgets [Demo]"; }
+ void initialize(QDesignerFormEditorInterface *)
+ {
+ if (m_initialized)
+ return;
+ m_initialized = true;
+ }
+ QString domXml() const { return m_domXml; }
+
+private:
+ const QString m_className;
+ const QString m_domXml;
+ bool m_initialized;
+};
+
+DemoPlugin::DemoPlugin(const QString &className) :
+ m_className(className),
+ m_domXml(customWidgetDomXml(className)),
+ m_initialized(false)
+{
+}
+
+class DeformPlugin : public QObject, public DemoPlugin
+{
+ Q_OBJECT
+
+public:
+ DeformPlugin(QObject *parent = 0) : QObject(parent), DemoPlugin(QLatin1String("PathDeformRendererEx")) { }
+ QString includeFile() const { return "deform.h"; }
+
+ QWidget *createWidget(QWidget *parent)
+ {
+ PathDeformRenderer *deform = new PathDeformRendererEx(parent);
+ deform->setRadius(70);
+ deform->setAnimated(false);
+ deform->setFontSize(20);
+ deform->setText("Arthur Widgets Demo");
+
+ return deform;
+ }
+};
+
+class XFormRendererEx : public XFormView
+{
+ Q_OBJECT
+public:
+ XFormRendererEx(QWidget *parent) : XFormView(parent) {}
+ QSize sizeHint() const { return QSize(300, 200); }
+};
+
+class XFormPlugin : public QObject, public DemoPlugin
+{
+ Q_OBJECT
+public:
+ XFormPlugin(QObject *parent = 0) : QObject(parent), DemoPlugin(QLatin1String("XFormRendererEx")) { }
+ QString includeFile() const { return "xform.h"; }
+
+ QWidget *createWidget(QWidget *parent)
+ {
+ XFormRendererEx *xform = new XFormRendererEx(parent);
+ xform->setText("Qt - Hello World!!");
+ xform->setPixmap(QPixmap(":/trolltech/arthurplugin/bg1.jpg"));
+ return xform;
+ }
+};
+
+
+class GradientEditorPlugin : public QObject, public DemoPlugin
+{
+ Q_OBJECT
+public:
+ GradientEditorPlugin(QObject *parent = 0) : QObject(parent), DemoPlugin(QLatin1String("GradientEditor")) { }
+ QString includeFile() const { return "gradients.h"; }
+
+ QWidget *createWidget(QWidget *parent)
+ {
+ GradientEditor *editor = new GradientEditor(parent);
+ return editor;
+ }
+};
+
+class GradientRendererEx : public GradientRenderer
+{
+ Q_OBJECT
+public:
+ GradientRendererEx(QWidget *p) : GradientRenderer(p) { }
+ QSize sizeHint() const { return QSize(300, 200); }
+};
+
+class GradientRendererPlugin : public QObject, public DemoPlugin
+{
+ Q_OBJECT
+public:
+ GradientRendererPlugin(QObject *parent = 0) : QObject(parent), DemoPlugin(QLatin1String("GradientRendererEx")) { }
+ QString includeFile() const { return "gradients.h"; }
+
+ QWidget *createWidget(QWidget *parent)
+ {
+ GradientRenderer *renderer = new GradientRendererEx(parent);
+ renderer->setConicalGradient();
+ return renderer;
+ }
+};
+
+class PathStrokeRendererEx : public PathStrokeRenderer
+{
+ Q_OBJECT
+public:
+ PathStrokeRendererEx(QWidget *p) : PathStrokeRenderer(p) { }
+ QSize sizeHint() const { return QSize(300, 200); }
+};
+
+class StrokeRenderPlugin : public QObject, public DemoPlugin
+{
+ Q_OBJECT
+public:
+ StrokeRenderPlugin(QObject *parent = 0) : QObject(parent), DemoPlugin(QLatin1String("PathStrokeRendererEx")) { }
+ QString includeFile() const { return "pathstroke.h"; }
+
+ QWidget *createWidget(QWidget *parent)
+ {
+ PathStrokeRenderer *stroke = new PathStrokeRendererEx(parent);
+ return stroke;
+ }
+};
+
+
+class CompositionModePlugin : public QObject, public DemoPlugin
+{
+ Q_OBJECT
+public:
+ CompositionModePlugin(QObject *parent = 0) : QObject(parent), DemoPlugin(QLatin1String("CompositionRenderer")) { }
+ QString includeFile() const { return "composition.h"; }
+
+ QWidget *createWidget(QWidget *parent)
+ {
+ CompositionRenderer *renderer = new CompositionRenderer(parent);
+ renderer->setAnimationEnabled(false);
+ return renderer;
+ }
+};
+
+
+class ArthurPlugins : public QObject, public QDesignerCustomWidgetCollectionInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
+
+public:
+ ArthurPlugins(QObject *parent = 0);
+ QList<QDesignerCustomWidgetInterface*> customWidgets() const { return m_plugins; }
+
+private:
+ QList<QDesignerCustomWidgetInterface *> m_plugins;
+};
+
+ArthurPlugins::ArthurPlugins(QObject *parent) :
+ QObject(parent)
+{
+ m_plugins << new DeformPlugin(this)
+ << new XFormPlugin(this)
+ << new GradientEditorPlugin(this)
+ << new GradientRendererPlugin(this)
+ << new StrokeRenderPlugin(this)
+ << new CompositionModePlugin(this);
+}
+
+#include "plugin.moc"
+
+Q_EXPORT_PLUGIN2(ArthurPlugins, ArthurPlugins)
diff --git a/demos/books/bookdelegate.cpp b/demos/books/bookdelegate.cpp
new file mode 100644
index 0000000..1322fd6
--- /dev/null
+++ b/demos/books/bookdelegate.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "bookdelegate.h"
+
+#include <QtGui>
+
+BookDelegate::BookDelegate(QObject *parent)
+ : QSqlRelationalDelegate(parent), star(QPixmap(":images/star.png"))
+{
+}
+
+void BookDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ if (index.column() != 5) {
+ QStyleOptionViewItemV3 opt = option;
+ opt.rect.adjust(0, 0, -1, -1); // since we draw the grid ourselves
+ QSqlRelationalDelegate::paint(painter, opt, index);
+ } else {
+ const QAbstractItemModel *model = index.model();
+ QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ?
+ (option.state & QStyle::State_Active) ? QPalette::Normal : QPalette::Inactive : QPalette::Disabled;
+
+ if (option.state & QStyle::State_Selected)
+ painter->fillRect(option.rect, option.palette.color(cg, QPalette::Highlight));
+
+ int rating = model->data(index, Qt::DisplayRole).toInt();
+ int width = star.width();
+ int height = star.height();
+ int x = option.rect.x();
+ int y = option.rect.y() + (option.rect.height() / 2) - (height / 2);
+ for (int i = 0; i < rating; ++i) {
+ painter->drawPixmap(x, y, star);
+ x += width;
+ }
+ drawFocus(painter, option, option.rect.adjusted(0, 0, -1, -1)); // since we draw the grid ourselves
+ }
+
+ QPen pen = painter->pen();
+ painter->setPen(option.palette.color(QPalette::Mid));
+ painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
+ painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
+ painter->setPen(pen);
+}
+
+QSize BookDelegate::sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ if (index.column() == 5)
+ return QSize(5 * star.width(), star.height()) + QSize(1, 1);
+
+ return QSqlRelationalDelegate::sizeHint(option, index) + QSize(1, 1); // since we draw the grid ourselves
+}
+
+bool BookDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index)
+{
+ if (index.column() != 5)
+ return QSqlRelationalDelegate::editorEvent(event, model, option, index);
+
+ if (event->type() == QEvent::MouseButtonPress) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
+ int stars = qBound(0, int(0.7 + qreal(mouseEvent->pos().x()
+ - option.rect.x()) / star.width()), 5);
+ model->setData(index, QVariant(stars));
+ return false; //so that the selection can change
+ }
+
+ return true;
+}
+
+QWidget *BookDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ if (index.column() != 4)
+ return QSqlRelationalDelegate::createEditor(parent, option, index);
+
+ // for editing the year, return a spinbox with a range from -1000 to 2100.
+ QSpinBox *sb = new QSpinBox(parent);
+ sb->setFrame(false);
+ sb->setMaximum(2100);
+ sb->setMinimum(-1000);
+
+ return sb;
+}
+
diff --git a/demos/books/bookdelegate.h b/demos/books/bookdelegate.h
new file mode 100644
index 0000000..fb32335
--- /dev/null
+++ b/demos/books/bookdelegate.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BOOKDELEGATE_H
+#define BOOKDELEGATE_H
+
+#include <QModelIndex>
+#include <QPixmap>
+#include <QSize>
+#include <QSqlRelationalDelegate>
+
+QT_FORWARD_DECLARE_CLASS(QPainter)
+
+class BookDelegate : public QSqlRelationalDelegate
+{
+public:
+ BookDelegate(QObject *parent);
+
+ void paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+ bool editorEvent(QEvent *event, QAbstractItemModel *model,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index);
+
+ QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+
+private:
+ QPixmap star;
+};
+
+#endif
diff --git a/demos/books/books.pro b/demos/books/books.pro
new file mode 100644
index 0000000..94b049a
--- /dev/null
+++ b/demos/books/books.pro
@@ -0,0 +1,23 @@
+TEMPLATE = app
+INCLUDEPATH += .
+
+HEADERS = bookdelegate.h bookwindow.h initdb.h
+RESOURCES = books.qrc
+SOURCES = bookdelegate.cpp main.cpp bookwindow.cpp
+FORMS = bookwindow.ui
+
+QT += sql
+
+target.path = $$[QT_INSTALL_DEMOS]/books
+sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS *.pro images
+sources.path = $$[QT_INSTALL_DEMOS]/books
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
+wince*: {
+ CONFIG(debug, debug|release):sqlPlugins.sources = $$QT_BUILD_TREE/plugins/sqldrivers/*d4.dll
+ CONFIG(release, debug|release):sqlPlugins.sources = $$QT_BUILD_TREE/plugins/sqldrivers/*[^d]4.dll
+ sqlPlugins.path = sqldrivers
+ DEPLOYMENT += sqlPlugins
+} \ No newline at end of file
diff --git a/demos/books/books.qrc b/demos/books/books.qrc
new file mode 100644
index 0000000..342638e
--- /dev/null
+++ b/demos/books/books.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>images/star.png</file>
+</qresource>
+</RCC>
diff --git a/demos/books/bookwindow.cpp b/demos/books/bookwindow.cpp
new file mode 100644
index 0000000..e73f727
--- /dev/null
+++ b/demos/books/bookwindow.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "bookwindow.h"
+#include "bookdelegate.h"
+#include "initdb.h"
+
+#include <QtSql>
+
+BookWindow::BookWindow()
+{
+ ui.setupUi(this);
+
+ if (!QSqlDatabase::drivers().contains("QSQLITE"))
+ QMessageBox::critical(this, "Unable to load database", "This demo needs the SQLITE driver");
+
+ // initialize the database
+ QSqlError err = initDb();
+ if (err.type() != QSqlError::NoError) {
+ showError(err);
+ return;
+ }
+
+ // Create the data model
+ model = new QSqlRelationalTableModel(ui.bookTable);
+ model->setEditStrategy(QSqlTableModel::OnManualSubmit);
+ model->setTable("books");
+
+ // Remeber the indexes of the columns
+ authorIdx = model->fieldIndex("author");
+ genreIdx = model->fieldIndex("genre");
+
+ // Set the relations to the other database tables
+ model->setRelation(authorIdx, QSqlRelation("authors", "id", "name"));
+ model->setRelation(genreIdx, QSqlRelation("genres", "id", "name"));
+
+ // Set the localized header captions
+ model->setHeaderData(authorIdx, Qt::Horizontal, tr("Author Name"));
+ model->setHeaderData(genreIdx, Qt::Horizontal, tr("Genre"));
+ model->setHeaderData(model->fieldIndex("title"), Qt::Horizontal, tr("Title"));
+ model->setHeaderData(model->fieldIndex("year"), Qt::Horizontal, tr("Year"));
+ model->setHeaderData(model->fieldIndex("rating"), Qt::Horizontal, tr("Rating"));
+
+ // Populate the model
+ if (!model->select()) {
+ showError(model->lastError());
+ return;
+ }
+
+ // Set the model and hide the ID column
+ ui.bookTable->setModel(model);
+ ui.bookTable->setItemDelegate(new BookDelegate(ui.bookTable));
+ ui.bookTable->setColumnHidden(model->fieldIndex("id"), true);
+ ui.bookTable->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ // Initialize the Author combo box
+ ui.authorEdit->setModel(model->relationModel(authorIdx));
+ ui.authorEdit->setModelColumn(model->relationModel(authorIdx)->fieldIndex("name"));
+
+ ui.genreEdit->setModel(model->relationModel(genreIdx));
+ ui.genreEdit->setModelColumn(model->relationModel(genreIdx)->fieldIndex("name"));
+
+ QDataWidgetMapper *mapper = new QDataWidgetMapper(this);
+ mapper->setModel(model);
+ mapper->setItemDelegate(new BookDelegate(this));
+ mapper->addMapping(ui.titleEdit, model->fieldIndex("title"));
+ mapper->addMapping(ui.yearEdit, model->fieldIndex("year"));
+ mapper->addMapping(ui.authorEdit, authorIdx);
+ mapper->addMapping(ui.genreEdit, genreIdx);
+ mapper->addMapping(ui.ratingEdit, model->fieldIndex("rating"));
+
+ connect(ui.bookTable->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
+ mapper, SLOT(setCurrentModelIndex(QModelIndex)));
+
+ ui.bookTable->setCurrentIndex(model->index(0, 0));
+}
+
+void BookWindow::showError(const QSqlError &err)
+{
+ QMessageBox::critical(this, "Unable to initialize Database",
+ "Error initializing database: " + err.text());
+}
+
diff --git a/demos/books/bookwindow.h b/demos/books/bookwindow.h
new file mode 100644
index 0000000..3cc69d0
--- /dev/null
+++ b/demos/books/bookwindow.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BOOKWINDOW_H
+#define BOOKWINDOW_H
+
+#include <QtGui>
+#include <QtSql>
+
+#include "ui_bookwindow.h"
+
+
+class BookWindow: public QMainWindow
+{
+ Q_OBJECT
+public:
+ BookWindow();
+
+private:
+ void showError(const QSqlError &err);
+ Ui::BookWindow ui;
+ QSqlRelationalTableModel *model;
+ int authorIdx, genreIdx;
+};
+
+#endif
diff --git a/demos/books/bookwindow.ui b/demos/books/bookwindow.ui
new file mode 100644
index 0000000..659d324
--- /dev/null
+++ b/demos/books/bookwindow.ui
@@ -0,0 +1,149 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>BookWindow</class>
+ <widget class="QMainWindow" name="BookWindow" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>601</width>
+ <height>420</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Books</string>
+ </property>
+ <widget class="QWidget" name="centralWidget" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="title" >
+ <string>Books</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QTableView" name="bookTable" >
+ <property name="selectionBehavior" >
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="title" >
+ <string>Details</string>
+ </property>
+ <layout class="QFormLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>&lt;b>Title:&lt;/b></string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="titleEdit" >
+ <property name="enabled" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2_2_2_2" >
+ <property name="text" >
+ <string>&lt;b>Author: &lt;/b></string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="authorEdit" >
+ <property name="enabled" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>&lt;b>Genre:&lt;/b></string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QComboBox" name="genreEdit" >
+ <property name="enabled" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_4" >
+ <property name="text" >
+ <string>&lt;b>Year:&lt;/b></string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QSpinBox" name="yearEdit" >
+ <property name="enabled" >
+ <bool>true</bool>
+ </property>
+ <property name="prefix" >
+ <string/>
+ </property>
+ <property name="maximum" >
+ <number>2100</number>
+ </property>
+ <property name="minimum" >
+ <number>-1000</number>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>&lt;b>Rating:&lt;/b></string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QSpinBox" name="ratingEdit" >
+ <property name="maximum" >
+ <number>5</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <tabstops>
+ <tabstop>bookTable</tabstop>
+ <tabstop>titleEdit</tabstop>
+ <tabstop>authorEdit</tabstop>
+ <tabstop>genreEdit</tabstop>
+ <tabstop>yearEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/demos/books/images/star.png b/demos/books/images/star.png
new file mode 100644
index 0000000..87f4464
--- /dev/null
+++ b/demos/books/images/star.png
Binary files differ
diff --git a/demos/books/initdb.h b/demos/books/initdb.h
new file mode 100644
index 0000000..f9a94b7
--- /dev/null
+++ b/demos/books/initdb.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INITDB_H
+#define INITDB_H
+
+#include <QtSql>
+
+void addBook(QSqlQuery &q, const QString &title, int year, const QVariant &authorId,
+ const QVariant &genreId, int rating)
+{
+ q.addBindValue(title);
+ q.addBindValue(year);
+ q.addBindValue(authorId);
+ q.addBindValue(genreId);
+ q.addBindValue(rating);
+ q.exec();
+}
+
+QVariant addGenre(QSqlQuery &q, const QString &name)
+{
+ q.addBindValue(name);
+ q.exec();
+ return q.lastInsertId();
+}
+
+QVariant addAuthor(QSqlQuery &q, const QString &name, const QDate &birthdate)
+{
+ q.addBindValue(name);
+ q.addBindValue(birthdate);
+ q.exec();
+ return q.lastInsertId();
+}
+
+QSqlError initDb()
+{
+ QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
+ db.setDatabaseName(":memory:");
+
+ if (!db.open())
+ return db.lastError();
+
+ QStringList tables = db.tables();
+ if (tables.contains("books", Qt::CaseInsensitive)
+ && tables.contains("authors", Qt::CaseInsensitive))
+ return QSqlError();
+
+ QSqlQuery q;
+ if (!q.exec(QLatin1String("create table books(id integer primary key, title varchar, author integer, genre integer, year integer, rating integer)")))
+ return q.lastError();
+ if (!q.exec(QLatin1String("create table authors(id integer primary key, name varchar, birthdate date)")))
+ return q.lastError();
+ if (!q.exec(QLatin1String("create table genres(id integer primary key, name varchar)")))
+ return q.lastError();
+
+ if (!q.prepare(QLatin1String("insert into authors(name, birthdate) values(?, ?)")))
+ return q.lastError();
+ QVariant asimovId = addAuthor(q, QLatin1String("Isaac Asimov"), QDate(1920, 2, 1));
+ QVariant greeneId = addAuthor(q, QLatin1String("Graham Greene"), QDate(1904, 10, 2));
+ QVariant pratchettId = addAuthor(q, QLatin1String("Terry Pratchett"), QDate(1948, 4, 28));
+
+ if (!q.prepare(QLatin1String("insert into genres(name) values(?)")))
+ return q.lastError();
+ QVariant sfiction = addGenre(q, QLatin1String("Science Fiction"));
+ QVariant fiction = addGenre(q, QLatin1String("Fiction"));
+ QVariant fantasy = addGenre(q, QLatin1String("Fantasy"));
+
+ if (!q.prepare(QLatin1String("insert into books(title, year, author, genre, rating) values(?, ?, ?, ?, ?)")))
+ return q.lastError();
+ addBook(q, QLatin1String("Foundation"), 1951, asimovId, sfiction, 3);
+ addBook(q, QLatin1String("Foundation and Empire"), 1952, asimovId, sfiction, 4);
+ addBook(q, QLatin1String("Second Foundation"), 1953, asimovId, sfiction, 3);
+ addBook(q, QLatin1String("Foundation's Edge"), 1982, asimovId, sfiction, 3);
+ addBook(q, QLatin1String("Foundation and Earth"), 1986, asimovId, sfiction, 4);
+ addBook(q, QLatin1String("Prelude to Foundation"), 1988, asimovId, sfiction, 3);
+ addBook(q, QLatin1String("Forward the Foundation"), 1993, asimovId, sfiction, 3);
+ addBook(q, QLatin1String("The Power and the Glory"), 1940, greeneId, fiction, 4);
+ addBook(q, QLatin1String("The Third Man"), 1950, greeneId, fiction, 5);
+ addBook(q, QLatin1String("Our Man in Havana"), 1958, greeneId, fiction, 4);
+ addBook(q, QLatin1String("Guards! Guards!"), 1989, pratchettId, fantasy, 3);
+ addBook(q, QLatin1String("Night Watch"), 2002, pratchettId, fantasy, 3);
+ addBook(q, QLatin1String("Going Postal"), 2004, pratchettId, fantasy, 3);
+
+ return QSqlError();
+}
+
+#endif
diff --git a/demos/books/main.cpp b/demos/books/main.cpp
new file mode 100644
index 0000000..f3ae325
--- /dev/null
+++ b/demos/books/main.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "bookwindow.h"
+
+#include <QtGui>
+
+int main(int argc, char * argv[])
+{
+ Q_INIT_RESOURCE(books);
+
+ QApplication app(argc, argv);
+
+ BookWindow win;
+ win.show();
+
+ return app.exec();
+}
diff --git a/demos/boxes/3rdparty/fbm.c b/demos/boxes/3rdparty/fbm.c
new file mode 100644
index 0000000..98eb87a
--- /dev/null
+++ b/demos/boxes/3rdparty/fbm.c
@@ -0,0 +1,207 @@
+/*****************************************************************
+
+ Implementation of the fractional Brownian motion algorithm. These
+ functions were originally the work of F. Kenton Musgrave.
+ For documentation of the different functions please refer to the
+ book:
+ "Texturing and modeling: a procedural approach"
+ by David S. Ebert et. al.
+
+******************************************************************/
+
+#if defined (_MSC_VER)
+#include <qglobal.h>
+#endif
+
+#include <time.h>
+#include <stdlib.h>
+#include "fbm.h"
+
+#if defined(Q_CC_MSVC)
+#pragma warning(disable:4244)
+#endif
+
+/* Definitions used by the noise2() functions */
+
+//#define B 0x100
+//#define BM 0xff
+#define B 0x20
+#define BM 0x1f
+
+#define N 0x1000
+#define NP 12 /* 2^N */
+#define NM 0xfff
+
+static int p[B + B + 2];
+static float g3[B + B + 2][3];
+static float g2[B + B + 2][2];
+static float g1[B + B + 2];
+static int start = 1;
+
+static void init(void);
+
+#define s_curve(t) ( t * t * (3. - 2. * t) )
+
+#define lerp(t, a, b) ( a + t * (b - a) )
+
+#define setup(i,b0,b1,r0,r1)\
+ t = vec[i] + N;\
+ b0 = ((int)t) & BM;\
+ b1 = (b0+1) & BM;\
+ r0 = t - (int)t;\
+ r1 = r0 - 1.;
+#define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )
+
+/* Fractional Brownian Motion function */
+
+double fBm( Vector point, double H, double lacunarity, double octaves,
+ int init )
+{
+
+ double value, frequency, remainder;
+ int i;
+ static double exponent_array[10];
+ float vec[3];
+
+ /* precompute and store spectral weights */
+ if ( init ) {
+ start = 1;
+ srand( time(0) );
+ /* seize required memory for exponent_array */
+ frequency = 1.0;
+ for (i=0; i<=octaves; i++) {
+ /* compute weight for each frequency */
+ exponent_array[i] = pow( frequency, -H );
+ frequency *= lacunarity;
+ }
+ }
+
+ value = 0.0; /* initialize vars to proper values */
+ frequency = 1.0;
+ vec[0]=point.x;
+ vec[1]=point.y;
+ vec[2]=point.z;
+
+
+ /* inner loop of spectral construction */
+ for (i=0; i<octaves; i++) {
+ /* value += noise3( vec ) * exponent_array[i];*/
+ value += noise3( vec ) * exponent_array[i];
+ vec[0] *= lacunarity;
+ vec[1] *= lacunarity;
+ vec[2] *= lacunarity;
+ } /* for */
+
+ remainder = octaves - (int)octaves;
+ if ( remainder ) /* add in ``octaves'' remainder */
+ /* ``i'' and spatial freq. are preset in loop above */
+ value += remainder * noise3( vec ) * exponent_array[i];
+
+ return( value );
+
+} /* fBm() */
+
+
+float noise3(float vec[3])
+{
+ int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
+ float rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v;
+ register int i, j;
+
+ if (start) {
+ start = 0;
+ init();
+ }
+
+ setup(0, bx0,bx1, rx0,rx1);
+ setup(1, by0,by1, ry0,ry1);
+ setup(2, bz0,bz1, rz0,rz1);
+
+ i = p[ bx0 ];
+ j = p[ bx1 ];
+
+ b00 = p[ i + by0 ];
+ b10 = p[ j + by0 ];
+ b01 = p[ i + by1 ];
+ b11 = p[ j + by1 ];
+
+ t = s_curve(rx0);
+ sy = s_curve(ry0);
+ sz = s_curve(rz0);
+
+
+ q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0);
+ q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0);
+ a = lerp(t, u, v);
+
+ q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0);
+ q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0);
+ b = lerp(t, u, v);
+
+ c = lerp(sy, a, b);
+
+ q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1);
+ q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1);
+ a = lerp(t, u, v);
+
+ q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1);
+ q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1);
+ b = lerp(t, u, v);
+
+ d = lerp(sy, a, b);
+
+ return lerp(sz, c, d);
+}
+
+static void normalize2(float v[2])
+{
+ float s;
+
+ s = sqrt(v[0] * v[0] + v[1] * v[1]);
+ v[0] = v[0] / s;
+ v[1] = v[1] / s;
+}
+
+static void normalize3(float v[3])
+{
+ float s;
+
+ s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ v[0] = v[0] / s;
+ v[1] = v[1] / s;
+ v[2] = v[2] / s;
+}
+
+static void init(void)
+{
+ int i, j, k;
+
+ for (i = 0 ; i < B ; i++) {
+ p[i] = i;
+
+ g1[i] = (float)((rand() % (B + B)) - B) / B;
+
+ for (j = 0 ; j < 2 ; j++)
+ g2[i][j] = (float)((rand() % (B + B)) - B) / B;
+ normalize2(g2[i]);
+
+ for (j = 0 ; j < 3 ; j++)
+ g3[i][j] = (float)((rand() % (B + B)) - B) / B;
+ normalize3(g3[i]);
+ }
+
+ while (--i) {
+ k = p[i];
+ p[i] = p[j = rand() % B];
+ p[j] = k;
+ }
+
+ for (i = 0 ; i < B + 2 ; i++) {
+ p[B + i] = p[i];
+ g1[B + i] = g1[i];
+ for (j = 0 ; j < 2 ; j++)
+ g2[B + i][j] = g2[i][j];
+ for (j = 0 ; j < 3 ; j++)
+ g3[B + i][j] = g3[i][j];
+ }
+}
diff --git a/demos/boxes/3rdparty/fbm.h b/demos/boxes/3rdparty/fbm.h
new file mode 100644
index 0000000..b8a4a99
--- /dev/null
+++ b/demos/boxes/3rdparty/fbm.h
@@ -0,0 +1,40 @@
+/*****************************************************************
+
+ Prototypes for the fractional Brownian motion algorithm. These
+ functions were originally the work of F. Kenton Musgrave. For
+ documentation of the different functions please refer to the book:
+ "Texturing and modeling: a procedural approach"
+ by David S. Ebert et. al.
+
+******************************************************************/
+
+#ifndef _fbm_h
+#define _fbm_h
+
+#include <math.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#define TRUE 1
+//#define FALSE 0
+
+typedef struct {
+ double x;
+ double y;
+ double z;
+} Vector;
+
+float noise3(float vec[]);
+double fBm( Vector point, double H, double lacunarity, double octaves,
+ int init );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+
diff --git a/demos/boxes/basic.fsh b/demos/boxes/basic.fsh
new file mode 100644
index 0000000..06ef24a
--- /dev/null
+++ b/demos/boxes/basic.fsh
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform vec4 basicColor;
+
+void main()
+{
+ vec3 N = normalize(normal);
+ // assume directional light
+
+ gl_MaterialParameters M = gl_FrontMaterial;
+
+ float NdotL = dot(N, lightDirection.xyz);
+ float RdotL = dot(reflect(normalize(position), N), lightDirection.xyz);
+
+ vec3 absN = abs(gl_TexCoord[1].xyz);
+ vec3 texCoord;
+ if (absN.x > absN.y && absN.x > absN.z)
+ texCoord = gl_TexCoord[1].yzx;
+ else if (absN.y > absN.z)
+ texCoord = gl_TexCoord[1].zxy;
+ else
+ texCoord = gl_TexCoord[1].xyz;
+ texCoord.y *= -sign(texCoord.z);
+ texCoord += 0.5;
+
+ vec4 texColor = texture2D(tex, texCoord.xy);
+ vec4 unlitColor = gl_Color * mix(basicColor, vec4(texColor.xyz, 1.0), texColor.w);
+ gl_FragColor = (ambient + diffuse * max(NdotL, 0.0)) * unlitColor +
+ M.specular * specular * pow(max(RdotL, 0.0), M.shininess);
+}
diff --git a/demos/boxes/basic.vsh b/demos/boxes/basic.vsh
new file mode 100644
index 0000000..5a02df2
--- /dev/null
+++ b/demos/boxes/basic.vsh
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform mat4 view;
+
+void main()
+{
+ gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_TexCoord[1] = gl_Vertex;
+ specular = gl_LightSource[0].specular;
+ ambient = gl_LightSource[0].ambient;
+ diffuse = gl_LightSource[0].diffuse;
+ lightDirection = view * gl_LightSource[0].position;
+
+ normal = gl_NormalMatrix * gl_Normal;
+ position = (gl_ModelViewMatrix * gl_Vertex).xyz;
+
+ gl_FrontColor = gl_Color;
+ gl_Position = ftransform();
+}
diff --git a/demos/boxes/boxes.pro b/demos/boxes/boxes.pro
new file mode 100644
index 0000000..6c1a331
--- /dev/null
+++ b/demos/boxes/boxes.pro
@@ -0,0 +1,50 @@
+######################################################################
+# Automatically generated by qmake (2.01a) ma 3. nov 17:33:30 2008
+######################################################################
+
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+
+# Input
+HEADERS += 3rdparty/fbm.h \
+ glbuffers.h \
+ glextensions.h \
+ glshaders.h \
+ gltrianglemesh.h \
+ qtbox.h \
+ roundedbox.h \
+ scene.h \
+ trackball.h \
+ vector.h
+SOURCES += 3rdparty/fbm.c \
+ glbuffers.cpp \
+ glextensions.cpp \
+ glshaders.cpp \
+ main.cpp \
+ qtbox.cpp \
+ roundedbox.cpp \
+ scene.cpp \
+ trackball.cpp
+
+RESOURCES += boxes.qrc
+
+QT += opengl
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/boxes
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.html *.jpg *.png *.fsh *.vsh *.par
+sources.files -= 3rdparty/fbm.h 3rdparty/fbm.c
+sources.files += 3rdparty
+sources.path = $$[QT_INSTALL_DEMOS]/boxes
+INSTALLS += target sources
+
+wince*: {
+ DEPLOYMENT_PLUGIN += qjpeg
+}
+
+win32-msvc* {
+ QMAKE_CXXFLAGS += /Zm1200
+ QMAKE_CFLAGS += /Zm1200
+}
diff --git a/demos/boxes/boxes.qrc b/demos/boxes/boxes.qrc
new file mode 100644
index 0000000..d27506d
--- /dev/null
+++ b/demos/boxes/boxes.qrc
@@ -0,0 +1,25 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/res/boxes">
+ <file>cubemap_negx.jpg</file>
+ <file>cubemap_negy.jpg</file>
+ <file>cubemap_negz.jpg</file>
+ <file>cubemap_posx.jpg</file>
+ <file>cubemap_posy.jpg</file>
+ <file>cubemap_posz.jpg</file>
+ <file>square.jpg</file>
+ <file>basic.vsh</file>
+ <file>basic.fsh</file>
+ <file>dotted.fsh</file>
+ <file>fresnel.fsh</file>
+ <file>glass.fsh</file>
+ <file>granite.fsh</file>
+ <file>marble.fsh</file>
+ <file>reflection.fsh</file>
+ <file>refraction.fsh</file>
+ <file>wood.fsh</file>
+ <file>parameters.par</file>
+ <file>qt-logo.png</file>
+ <file>smiley.png</file>
+ <file>qt-logo.jpg</file>
+</qresource>
+</RCC>
diff --git a/demos/boxes/cubemap_negx.jpg b/demos/boxes/cubemap_negx.jpg
new file mode 100644
index 0000000..07c282e
--- /dev/null
+++ b/demos/boxes/cubemap_negx.jpg
Binary files differ
diff --git a/demos/boxes/cubemap_negy.jpg b/demos/boxes/cubemap_negy.jpg
new file mode 100644
index 0000000..46cd2f9
--- /dev/null
+++ b/demos/boxes/cubemap_negy.jpg
Binary files differ
diff --git a/demos/boxes/cubemap_negz.jpg b/demos/boxes/cubemap_negz.jpg
new file mode 100644
index 0000000..40c01dd
--- /dev/null
+++ b/demos/boxes/cubemap_negz.jpg
Binary files differ
diff --git a/demos/boxes/cubemap_posx.jpg b/demos/boxes/cubemap_posx.jpg
new file mode 100644
index 0000000..0b42e8a
--- /dev/null
+++ b/demos/boxes/cubemap_posx.jpg
Binary files differ
diff --git a/demos/boxes/cubemap_posy.jpg b/demos/boxes/cubemap_posy.jpg
new file mode 100644
index 0000000..2aca9b1
--- /dev/null
+++ b/demos/boxes/cubemap_posy.jpg
Binary files differ
diff --git a/demos/boxes/cubemap_posz.jpg b/demos/boxes/cubemap_posz.jpg
new file mode 100644
index 0000000..2e49173
--- /dev/null
+++ b/demos/boxes/cubemap_posz.jpg
Binary files differ
diff --git a/demos/boxes/dotted.fsh b/demos/boxes/dotted.fsh
new file mode 100644
index 0000000..26425f6
--- /dev/null
+++ b/demos/boxes/dotted.fsh
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+
+void main()
+{
+ vec3 N = normalize(normal);
+
+ gl_MaterialParameters M = gl_FrontMaterial;
+
+ // assume directional light
+ float NdotL = dot(N, lightDirection.xyz);
+ float RdotL = dot(reflect(normalize(position), N), lightDirection.xyz);
+
+ float r1 = length(fract(7.0 * gl_TexCoord[1].xyz) - 0.5);
+ float r2 = length(fract(5.0 * gl_TexCoord[1].xyz + 0.2) - 0.5);
+ float r3 = length(fract(11.0 * gl_TexCoord[1].xyz + 0.7) - 0.5);
+ vec4 rs = vec4(r1, r2, r3, 0.0);
+
+ vec4 unlitColor = gl_Color * (0.8 - clamp(10.0 * (0.4 - rs), 0.0, 0.2));
+ unlitColor.w = 1.0;
+ gl_FragColor = (ambient + diffuse * max(NdotL, 0.0)) * unlitColor +
+ M.specular * specular * pow(max(RdotL, 0.0), M.shininess);
+}
diff --git a/demos/boxes/fresnel.fsh b/demos/boxes/fresnel.fsh
new file mode 100644
index 0000000..dd98061
--- /dev/null
+++ b/demos/boxes/fresnel.fsh
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform samplerCube env;
+uniform mat4 view;
+uniform vec4 basicColor;
+
+void main()
+{
+ vec3 N = normalize(normal);
+ // assume directional light
+
+ gl_MaterialParameters M = gl_FrontMaterial;
+
+ float NdotL = dot(N, lightDirection.xyz);
+ float RdotL = dot(reflect(normalize(position), N), lightDirection.xyz);
+
+ vec3 absN = abs(gl_TexCoord[1].xyz);
+ vec3 texCoord;
+ if (absN.x > absN.y && absN.x > absN.z)
+ texCoord = gl_TexCoord[1].yzx;
+ else if (absN.y > absN.z)
+ texCoord = gl_TexCoord[1].zxy;
+ else
+ texCoord = gl_TexCoord[1].xyz;
+ texCoord.y *= -sign(texCoord.z);
+ texCoord += 0.5;
+
+ vec4 texColor = texture2D(tex, texCoord.xy);
+ vec4 unlitColor = gl_Color * mix(basicColor, vec4(texColor.xyz, 1.0), texColor.w);
+ vec4 litColor = (ambient + diffuse * max(NdotL, 0.0)) * unlitColor +
+ M.specular * specular * pow(max(RdotL, 0.0), M.shininess);
+
+ vec3 R = 2.0 * dot(-position, N) * N + position;
+ vec4 reflectedColor = textureCube(env, R * mat3(view[0].xyz, view[1].xyz, view[2].xyz));
+ gl_FragColor = mix(litColor, reflectedColor, 0.2 + 0.8 * pow(1.0 + dot(N, normalize(position)), 2.0));
+}
diff --git a/demos/boxes/glass.fsh b/demos/boxes/glass.fsh
new file mode 100644
index 0000000..2b59a0a
--- /dev/null
+++ b/demos/boxes/glass.fsh
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform samplerCube env;
+uniform mat4 view;
+
+// Some arbitrary values
+// Arrays don't work here on glsl < 120, apparently.
+//const float coeffs[6] = float[6](1.0/4.0, 1.0/4.1, 1.0/4.2, 1.0/4.3, 1.0/4.4, 1.0/4.5);
+float coeffs(int i)
+{
+ return 1.0 / (3.0 + 0.1 * float(i));
+}
+
+void main()
+{
+ vec3 N = normalize(normal);
+ vec3 I = -normalize(position);
+ mat3 V = mat3(view[0].xyz, view[1].xyz, view[2].xyz);
+ float IdotN = dot(I, N);
+ float scales[6];
+ vec3 C[6];
+ for (int i = 0; i < 6; ++i) {
+ scales[i] = (IdotN - sqrt(1.0 - coeffs(i) + coeffs(i) * (IdotN * IdotN)));
+ C[i] = textureCube(env, (-I + coeffs(i) * N) * V).xyz;
+ }
+ vec4 refractedColor = 0.25 * vec4(C[5].x + 2.0*C[0].x + C[1].x, C[1].y + 2.0*C[2].y + C[3].y,
+ C[3].z + 2.0*C[4].z + C[5].z, 4.0);
+
+ vec3 R = 2.0 * dot(-position, N) * N + position;
+ vec4 reflectedColor = textureCube(env, R * V);
+
+ gl_FragColor = mix(refractedColor, reflectedColor, 0.4 + 0.6 * pow(1.0 - IdotN, 2.0));
+}
diff --git a/demos/boxes/glbuffers.cpp b/demos/boxes/glbuffers.cpp
new file mode 100644
index 0000000..b2a594e
--- /dev/null
+++ b/demos/boxes/glbuffers.cpp
@@ -0,0 +1,390 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "glbuffers.h"
+
+//============================================================================//
+// GLTexture //
+//============================================================================//
+
+GLTexture::GLTexture() : m_texture(0), m_failed(false)
+{
+ glGenTextures(1, &m_texture);
+}
+
+GLTexture::~GLTexture()
+{
+ glDeleteTextures(1, &m_texture);
+}
+
+//============================================================================//
+// GLTexture2D //
+//============================================================================//
+
+GLTexture2D::GLTexture2D(int width, int height)
+{
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, 0);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ //glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+
+GLTexture2D::GLTexture2D(const QString& fileName, int width, int height)
+{
+ // TODO: Add error handling.
+ QImage image(fileName);
+
+ if (image.isNull()) {
+ m_failed = true;
+ return;
+ }
+
+ image = image.convertToFormat(QImage::Format_ARGB32);
+
+ //qDebug() << "Image size:" << image.width() << "x" << image.height();
+ if (width <= 0)
+ width = image.width();
+ if (height <= 0)
+ height = image.height();
+ if (width != image.width() || height != image.height())
+ image = image.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+
+ // Works on x86, so probably works on all little-endian systems.
+ // Does it work on big-endian systems?
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, image.width(), image.height(), 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ //glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+void GLTexture2D::load(int width, int height, QRgb *data)
+{
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, data);
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+void GLTexture2D::bind()
+{
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+ glEnable(GL_TEXTURE_2D);
+}
+
+void GLTexture2D::unbind()
+{
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+}
+
+
+//============================================================================//
+// GLTexture3D //
+//============================================================================//
+
+GLTexture3D::GLTexture3D(int width, int height, int depth)
+{
+ GLBUFFERS_ASSERT_OPENGL("GLTexture3D::GLTexture3D", glTexImage3D, return)
+
+ glBindTexture(GL_TEXTURE_3D, m_texture);
+ glTexImage3D(GL_TEXTURE_3D, 0, 4, width, height, depth, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, 0);
+
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ //glTexParameteri(GL_TEXTURE_3D, GL_GENERATE_MIPMAP, GL_TRUE);
+ glBindTexture(GL_TEXTURE_3D, 0);
+}
+
+void GLTexture3D::load(int width, int height, int depth, QRgb *data)
+{
+ GLBUFFERS_ASSERT_OPENGL("GLTexture3D::load", glTexImage3D, return)
+
+ glBindTexture(GL_TEXTURE_3D, m_texture);
+ glTexImage3D(GL_TEXTURE_3D, 0, 4, width, height, depth, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, data);
+ glBindTexture(GL_TEXTURE_3D, 0);
+}
+
+void GLTexture3D::bind()
+{
+ glBindTexture(GL_TEXTURE_3D, m_texture);
+ glEnable(GL_TEXTURE_3D);
+}
+
+void GLTexture3D::unbind()
+{
+ glBindTexture(GL_TEXTURE_3D, 0);
+ glDisable(GL_TEXTURE_3D);
+}
+
+//============================================================================//
+// GLTextureCube //
+//============================================================================//
+
+GLTextureCube::GLTextureCube(int size)
+{
+ glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
+
+ for (int i = 0; i < 6; ++i)
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 4, size, size, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, 0);
+
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+}
+
+GLTextureCube::GLTextureCube(const QStringList& fileNames, int size)
+{
+ // TODO: Add error handling.
+
+ glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
+
+ int index = 0;
+ foreach (QString file, fileNames) {
+ QImage image(file);
+ if (image.isNull()) {
+ m_failed = true;
+ break;
+ }
+
+ image = image.convertToFormat(QImage::Format_ARGB32);
+
+ //qDebug() << "Image size:" << image.width() << "x" << image.height();
+ if (size <= 0)
+ size = image.width();
+ if (size != image.width() || size != image.height())
+ image = image.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+
+ // Works on x86, so probably works on all little-endian systems.
+ // Does it work on big-endian systems?
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index, 0, 4, image.width(), image.height(), 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
+
+ if (++index == 6)
+ break;
+ }
+
+ // Clear remaining faces.
+ while (index < 6) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index, 0, 4, size, size, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, 0);
+ ++index;
+ }
+
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+}
+
+void GLTextureCube::load(int size, int face, QRgb *data)
+{
+ glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, 4, size, size, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, data);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+}
+
+void GLTextureCube::bind()
+{
+ glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
+ glEnable(GL_TEXTURE_CUBE_MAP);
+}
+
+void GLTextureCube::unbind()
+{
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+ glDisable(GL_TEXTURE_CUBE_MAP);
+}
+
+//============================================================================//
+// GLFrameBufferObject //
+//============================================================================//
+
+GLFrameBufferObject::GLFrameBufferObject(int width, int height)
+ : m_fbo(0)
+ , m_depthBuffer(0)
+ , m_width(width)
+ , m_height(height)
+ , m_failed(false)
+{
+ GLBUFFERS_ASSERT_OPENGL("GLFrameBufferObject::GLFrameBufferObject",
+ glGenFramebuffersEXT && glGenRenderbuffersEXT && glBindRenderbufferEXT && glRenderbufferStorageEXT, return)
+
+ // TODO: share depth buffers of same size
+ glGenFramebuffersEXT(1, &m_fbo);
+ //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glGenRenderbuffersEXT(1, &m_depthBuffer);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, m_width, m_height);
+ //glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer);
+ //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+}
+
+GLFrameBufferObject::~GLFrameBufferObject()
+{
+ GLBUFFERS_ASSERT_OPENGL("GLFrameBufferObject::~GLFrameBufferObject",
+ glDeleteFramebuffersEXT && glDeleteRenderbuffersEXT, return)
+
+ glDeleteFramebuffersEXT(1, &m_fbo);
+ glDeleteRenderbuffersEXT(1, &m_depthBuffer);
+}
+
+void GLFrameBufferObject::setAsRenderTarget(bool state)
+{
+ GLBUFFERS_ASSERT_OPENGL("GLFrameBufferObject::setAsRenderTarget", glBindFramebufferEXT, return)
+
+ if (state) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glPushAttrib(GL_VIEWPORT_BIT);
+ glViewport(0, 0, m_width, m_height);
+ } else {
+ glPopAttrib();
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ }
+}
+
+bool GLFrameBufferObject::isComplete()
+{
+ GLBUFFERS_ASSERT_OPENGL("GLFrameBufferObject::isComplete", glCheckFramebufferStatusEXT, return false)
+
+ return GL_FRAMEBUFFER_COMPLETE_EXT == glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+}
+
+//============================================================================//
+// GLRenderTargetCube //
+//============================================================================//
+
+GLRenderTargetCube::GLRenderTargetCube(int size)
+ : GLTextureCube(size)
+ , m_fbo(size, size)
+{
+}
+
+void GLRenderTargetCube::begin(int face)
+{
+ GLBUFFERS_ASSERT_OPENGL("GLRenderTargetCube::begin",
+ glFramebufferTexture2DEXT && glFramebufferRenderbufferEXT, return)
+
+ m_fbo.setAsRenderTarget(true);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, m_texture, 0);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_fbo.m_depthBuffer);
+}
+
+void GLRenderTargetCube::end()
+{
+ m_fbo.setAsRenderTarget(false);
+}
+
+void GLRenderTargetCube::getViewMatrix(gfx::Matrix4x4f& mat, int face)
+{
+ if (face < 0 || face >= 6) {
+ qWarning("GLRenderTargetCube::getViewMatrix: 'face' must be in the range [0, 6). (face == %d)", face);
+ return;
+ }
+
+ static int perm[6][3] = {
+ {2, 1, 0},
+ {2, 1, 0},
+ {0, 2, 1},
+ {0, 2, 1},
+ {0, 1, 2},
+ {0, 1, 2},
+ };
+
+ static float signs[6][3] = {
+ {-1.0f, -1.0f, -1.0f},
+ {+1.0f, -1.0f, +1.0f},
+ {+1.0f, +1.0f, -1.0f},
+ {+1.0f, -1.0f, +1.0f},
+ {+1.0f, -1.0f, -1.0f},
+ {-1.0f, -1.0f, +1.0f},
+ };
+
+ memset(mat.bits(), 0, sizeof(float) * 16);
+ for (int i = 0; i < 3; ++i)
+ mat(perm[face][i], i) = signs[face][i];
+ mat(3, 3) = 1.0f;
+}
+
+void GLRenderTargetCube::getProjectionMatrix(gfx::Matrix4x4f& mat, float nearZ, float farZ)
+{
+ float proj[] = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, (nearZ+farZ)/(nearZ-farZ), -1.0f,
+ 0.0f, 0.0f, 2.0f*nearZ*farZ/(nearZ-farZ), 0.0f,
+ };
+
+ memcpy(mat.bits(), proj, sizeof(float) * 16);
+}
diff --git a/demos/boxes/glbuffers.h b/demos/boxes/glbuffers.h
new file mode 100644
index 0000000..88de4e8
--- /dev/null
+++ b/demos/boxes/glbuffers.h
@@ -0,0 +1,362 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GLBUFFERS_H
+#define GLBUFFERS_H
+
+//#include <GL/glew.h>
+#include "glextensions.h"
+
+#include <QtGui>
+#include <QtOpenGL>
+
+#include "vector.h"
+
+#define BUFFER_OFFSET(i) ((char*)0 + (i))
+#define SIZE_OF_MEMBER(cls, member) sizeof(static_cast<cls *>(0)->member)
+
+#define GLBUFFERS_ASSERT_OPENGL(prefix, assertion, returnStatement) \
+if (m_failed || !(assertion)) { \
+ if (!m_failed) qCritical(prefix ": The necessary OpenGL functions are not available."); \
+ m_failed = true; \
+ returnStatement; \
+}
+
+class GLTexture
+{
+public:
+ GLTexture();
+ virtual ~GLTexture();
+ virtual void bind() = 0;
+ virtual void unbind() = 0;
+ virtual bool failed() const {return m_failed;}
+protected:
+ GLuint m_texture;
+ bool m_failed;
+};
+
+class GLFrameBufferObject
+{
+public:
+ friend class GLRenderTargetCube;
+ // friend class GLRenderTarget2D;
+
+ GLFrameBufferObject(int width, int height);
+ virtual ~GLFrameBufferObject();
+ bool isComplete();
+ virtual bool failed() const {return m_failed;}
+protected:
+ void setAsRenderTarget(bool state = true);
+ GLuint m_fbo;
+ GLuint m_depthBuffer;
+ int m_width, m_height;
+ bool m_failed;
+};
+
+class GLTexture2D : public GLTexture
+{
+public:
+ GLTexture2D(int width, int height);
+ GLTexture2D(const QString& fileName, int width = 0, int height = 0);
+ void load(int width, int height, QRgb *data);
+ virtual void bind();
+ virtual void unbind();
+};
+
+class GLTexture3D : public GLTexture
+{
+public:
+ GLTexture3D(int width, int height, int depth);
+ // TODO: Implement function below
+ //GLTexture3D(const QString& fileName, int width = 0, int height = 0);
+ void load(int width, int height, int depth, QRgb *data);
+ virtual void bind();
+ virtual void unbind();
+};
+
+class GLTextureCube : public GLTexture
+{
+public:
+ GLTextureCube(int size);
+ GLTextureCube(const QStringList& fileNames, int size = 0);
+ void load(int size, int face, QRgb *data);
+ virtual void bind();
+ virtual void unbind();
+};
+
+// TODO: Define and implement class below
+//class GLRenderTarget2D : public GLTexture2D
+
+class GLRenderTargetCube : public GLTextureCube
+{
+public:
+ GLRenderTargetCube(int size);
+ // begin rendering to one of the cube's faces. 0 <= face < 6
+ void begin(int face);
+ // end rendering
+ void end();
+ virtual bool failed() {return m_failed || m_fbo.failed();}
+
+ static void getViewMatrix(gfx::Matrix4x4f& mat, int face);
+ static void getProjectionMatrix(gfx::Matrix4x4f& mat, float nearZ, float farZ);
+private:
+ GLFrameBufferObject m_fbo;
+};
+
+struct VertexDescription
+{
+ enum
+ {
+ Null = 0, // Terminates a VertexDescription array
+ Position,
+ TexCoord,
+ Normal,
+ Color,
+ };
+ int field; // Position, TexCoord, Normal, Color
+ int type; // GL_FLOAT, GL_UNSIGNED_BYTE
+ int count; // number of elements
+ int offset; // field's offset into vertex struct
+ int index; // 0 (unused at the moment)
+};
+
+// Implementation of interleaved buffers.
+// 'T' is a struct which must include a null-terminated static array
+// 'VertexDescription* description'.
+// Example:
+/*
+struct Vertex
+{
+ GLfloat position[3];
+ GLfloat texCoord[2];
+ GLfloat normal[3];
+ GLbyte color[4];
+ static VertexDescription description[];
+};
+
+VertexDescription Vertex::description[] = {
+ {VertexDescription::Position, GL_FLOAT, SIZE_OF_MEMBER(Vertex, position) / sizeof(GLfloat), offsetof(Vertex, position), 0},
+ {VertexDescription::TexCoord, GL_FLOAT, SIZE_OF_MEMBER(Vertex, texCoord) / sizeof(GLfloat), offsetof(Vertex, texCoord), 0},
+ {VertexDescription::Normal, GL_FLOAT, SIZE_OF_MEMBER(Vertex, normal) / sizeof(GLfloat), offsetof(Vertex, normal), 0},
+ {VertexDescription::Color, GL_BYTE, SIZE_OF_MEMBER(Vertex, color) / sizeof(GLbyte), offsetof(Vertex, color), 0},
+ {VertexDescription::Null, 0, 0, 0, 0},
+};
+*/
+template<class T>
+class GLVertexBuffer
+{
+public:
+ GLVertexBuffer(int length, const T *data = 0, int mode = GL_STATIC_DRAW)
+ : m_length(0)
+ , m_mode(mode)
+ , m_buffer(0)
+ , m_failed(false)
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::GLVertexBuffer", glGenBuffers && glBindBuffer && glBufferData, return)
+
+ glGenBuffers(1, &m_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
+ glBufferData(GL_ARRAY_BUFFER, (m_length = length) * sizeof(T), data, mode);
+ }
+
+ ~GLVertexBuffer()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::~GLVertexBuffer", glDeleteBuffers, return)
+
+ glDeleteBuffers(1, &m_buffer);
+ }
+
+ void bind()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::bind", glBindBuffer, return)
+
+ glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
+ for (VertexDescription *desc = T::description; desc->field != VertexDescription::Null; ++desc) {
+ switch (desc->field) {
+ case VertexDescription::Position:
+ glVertexPointer(desc->count, desc->type, sizeof(T), BUFFER_OFFSET(desc->offset));
+ glEnableClientState(GL_VERTEX_ARRAY);
+ break;
+ case VertexDescription::TexCoord:
+ glTexCoordPointer(desc->count, desc->type, sizeof(T), BUFFER_OFFSET(desc->offset));
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ break;
+ case VertexDescription::Normal:
+ glNormalPointer(desc->type, sizeof(T), BUFFER_OFFSET(desc->offset));
+ glEnableClientState(GL_NORMAL_ARRAY);
+ break;
+ case VertexDescription::Color:
+ glColorPointer(desc->count, desc->type, sizeof(T), BUFFER_OFFSET(desc->offset));
+ glEnableClientState(GL_COLOR_ARRAY);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ void unbind()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::unbind", glBindBuffer, return)
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ for (VertexDescription *desc = T::description; desc->field != VertexDescription::Null; ++desc) {
+ switch (desc->field) {
+ case VertexDescription::Position:
+ glDisableClientState(GL_VERTEX_ARRAY);
+ break;
+ case VertexDescription::TexCoord:
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ break;
+ case VertexDescription::Normal:
+ glDisableClientState(GL_NORMAL_ARRAY);
+ break;
+ case VertexDescription::Color:
+ glDisableClientState(GL_COLOR_ARRAY);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ int length() const {return m_length;}
+
+ T *lock()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::lock", glBindBuffer && glMapBuffer, return 0)
+
+ glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
+ //glBufferData(GL_ARRAY_BUFFER, m_length, NULL, m_mode);
+ GLvoid* buffer = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
+ m_failed = (buffer == 0);
+ return reinterpret_cast<T *>(buffer);
+ }
+
+ void unlock()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::unlock", glBindBuffer && glUnmapBuffer, return)
+
+ glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ }
+
+ bool failed()
+ {
+ return m_failed;
+ }
+
+private:
+ int m_length, m_mode;
+ GLuint m_buffer;
+ bool m_failed;
+};
+
+template<class T>
+class GLIndexBuffer
+{
+public:
+ GLIndexBuffer(int length, const T *data = 0, int mode = GL_STATIC_DRAW)
+ : m_length(0)
+ , m_mode(mode)
+ , m_buffer(0)
+ , m_failed(false)
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::GLIndexBuffer", glGenBuffers && glBindBuffer && glBufferData, return)
+
+ glGenBuffers(1, &m_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, (m_length = length) * sizeof(T), data, mode);
+ }
+
+ ~GLIndexBuffer()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::~GLIndexBuffer", glDeleteBuffers, return)
+
+ glDeleteBuffers(1, &m_buffer);
+ }
+
+ void bind()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::bind", glBindBuffer, return)
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
+ }
+
+ void unbind()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::unbind", glBindBuffer, return)
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ int length() const {return m_length;}
+
+ T *lock()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::lock", glBindBuffer && glMapBuffer, return 0)
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
+ GLvoid* buffer = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_WRITE);
+ m_failed = (buffer == 0);
+ return reinterpret_cast<T *>(buffer);
+ }
+
+ void unlock()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::unlock", glBindBuffer && glUnmapBuffer, return)
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+ }
+
+ bool failed()
+ {
+ return m_failed;
+ }
+
+private:
+ int m_length, m_mode;
+ GLuint m_buffer;
+ bool m_failed;
+};
+
+#endif
diff --git a/demos/boxes/glextensions.cpp b/demos/boxes/glextensions.cpp
new file mode 100644
index 0000000..59256a8
--- /dev/null
+++ b/demos/boxes/glextensions.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "glextensions.h"
+
+#define RESOLVE_GL_FUNC(f) ok &= bool((f = (_gl##f) context->getProcAddress(QLatin1String("gl" #f))));
+
+bool GLExtensionFunctions::resolve(const QGLContext *context)
+{
+ bool ok = true;
+
+ RESOLVE_GL_FUNC(CreateShaderObjectARB)
+ RESOLVE_GL_FUNC(ShaderSourceARB)
+ RESOLVE_GL_FUNC(CompileShaderARB)
+ RESOLVE_GL_FUNC(GetObjectParameterivARB)
+ RESOLVE_GL_FUNC(DeleteObjectARB)
+ RESOLVE_GL_FUNC(GetInfoLogARB)
+ RESOLVE_GL_FUNC(CreateProgramObjectARB)
+ RESOLVE_GL_FUNC(AttachObjectARB)
+ RESOLVE_GL_FUNC(DetachObjectARB)
+ RESOLVE_GL_FUNC(LinkProgramARB)
+ RESOLVE_GL_FUNC(UseProgramObjectARB)
+ RESOLVE_GL_FUNC(GetUniformLocationARB)
+ RESOLVE_GL_FUNC(Uniform1iARB)
+ RESOLVE_GL_FUNC(Uniform1fARB)
+ RESOLVE_GL_FUNC(Uniform4fARB)
+ RESOLVE_GL_FUNC(UniformMatrix4fvARB)
+
+ RESOLVE_GL_FUNC(GenFramebuffersEXT)
+ RESOLVE_GL_FUNC(GenRenderbuffersEXT)
+ RESOLVE_GL_FUNC(BindRenderbufferEXT)
+ RESOLVE_GL_FUNC(RenderbufferStorageEXT)
+ RESOLVE_GL_FUNC(DeleteFramebuffersEXT)
+ RESOLVE_GL_FUNC(DeleteRenderbuffersEXT)
+ RESOLVE_GL_FUNC(BindFramebufferEXT)
+ RESOLVE_GL_FUNC(FramebufferTexture2DEXT)
+ RESOLVE_GL_FUNC(FramebufferRenderbufferEXT)
+ RESOLVE_GL_FUNC(CheckFramebufferStatusEXT)
+
+ RESOLVE_GL_FUNC(ActiveTexture)
+ RESOLVE_GL_FUNC(TexImage3D)
+
+ RESOLVE_GL_FUNC(GenBuffers)
+ RESOLVE_GL_FUNC(BindBuffer)
+ RESOLVE_GL_FUNC(BufferData)
+ RESOLVE_GL_FUNC(DeleteBuffers)
+ RESOLVE_GL_FUNC(MapBuffer)
+ RESOLVE_GL_FUNC(UnmapBuffer)
+
+ return ok;
+}
+
+bool GLExtensionFunctions::glslSupported() {
+ return CreateShaderObjectARB
+ && CreateShaderObjectARB
+ && ShaderSourceARB
+ && CompileShaderARB
+ && GetObjectParameterivARB
+ && DeleteObjectARB
+ && GetInfoLogARB
+ && CreateProgramObjectARB
+ && AttachObjectARB
+ && DetachObjectARB
+ && LinkProgramARB
+ && UseProgramObjectARB
+ && GetUniformLocationARB
+ && Uniform1iARB
+ && Uniform1fARB
+ && Uniform4fARB
+ && UniformMatrix4fvARB;
+}
+
+bool GLExtensionFunctions::fboSupported() {
+ return GenFramebuffersEXT
+ && GenRenderbuffersEXT
+ && BindRenderbufferEXT
+ && RenderbufferStorageEXT
+ && DeleteFramebuffersEXT
+ && DeleteRenderbuffersEXT
+ && BindFramebufferEXT
+ && FramebufferTexture2DEXT
+ && FramebufferRenderbufferEXT
+ && CheckFramebufferStatusEXT;
+}
+
+bool GLExtensionFunctions::openGL15Supported() {
+ return ActiveTexture
+ && TexImage3D
+ && GenBuffers
+ && BindBuffer
+ && BufferData
+ && DeleteBuffers
+ && MapBuffer
+ && UnmapBuffer;
+}
+
+#undef RESOLVE_GL_FUNC
diff --git a/demos/boxes/glextensions.h b/demos/boxes/glextensions.h
new file mode 100644
index 0000000..74617d6
--- /dev/null
+++ b/demos/boxes/glextensions.h
@@ -0,0 +1,284 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GLEXTENSIONS_H
+#define GLEXTENSIONS_H
+
+#include <QtOpenGL>
+
+/*
+Functions resolved:
+
+glCreateShaderObjectARB
+glShaderSourceARB
+glCompileShaderARB
+glGetObjectParameterivARB
+glDeleteObjectARB
+glGetInfoLogARB
+glCreateProgramObjectARB
+glAttachObjectARB
+glDetachObjectARB
+glLinkProgramARB
+glUseProgramObjectARB
+glGetUniformLocationARB
+glUniform1iARB
+glUniform1fARB
+glUniform4fARB
+glUniformMatrix4fvARB
+
+glGenFramebuffersEXT
+glGenRenderbuffersEXT
+glBindRenderbufferEXT
+glRenderbufferStorageEXT
+glDeleteFramebuffersEXT
+glDeleteRenderbuffersEXT
+glBindFramebufferEXT
+glFramebufferTexture2DEXT
+glFramebufferRenderbufferEXT
+glCheckFramebufferStatusEXT
+
+glActiveTexture
+glTexImage3D
+
+glGenBuffers
+glBindBuffer
+glBufferData
+glDeleteBuffers
+glMapBuffer
+glUnmapBuffer
+*/
+
+#ifndef Q_WS_MAC
+# ifndef APIENTRYP
+# ifdef APIENTRY
+# define APIENTRYP APIENTRY *
+# else
+# define APIENTRY
+# define APIENTRYP *
+# endif
+# endif
+#else
+# define APIENTRY
+# define APIENTRYP *
+#endif
+
+#ifndef GL_VERSION_1_2
+#define GL_TEXTURE_3D 0x806F
+#define GL_TEXTURE_WRAP_R 0x8072
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_BGRA 0x80E1
+#endif
+
+#ifndef GL_VERSION_1_3
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+//#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+//#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+//#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+//#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+//#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#endif
+
+#ifndef GL_VERSION_1_5
+typedef ptrdiff_t GLsizeiptr;
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_READ_WRITE 0x88BA
+#define GL_STATIC_DRAW 0x88E4
+#endif
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_RENDERBUFFER_EXT 0x8D41
+#define GL_FRAMEBUFFER_EXT 0x8D40
+#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
+#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
+#define GL_DEPTH_ATTACHMENT_EXT 0x8D00
+#endif
+
+#ifndef GL_ARB_vertex_shader
+#define GL_VERTEX_SHADER_ARB 0x8B31
+#endif
+
+#ifndef GL_ARB_fragment_shader
+#define GL_FRAGMENT_SHADER_ARB 0x8B30
+#endif
+
+#ifndef GL_ARB_shader_objects
+typedef char GLcharARB;
+typedef unsigned int GLhandleARB;
+#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81
+#define GL_OBJECT_LINK_STATUS_ARB 0x8B82
+#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84
+#endif
+
+typedef GLhandleARB (APIENTRY *_glCreateShaderObjectARB) (GLenum);
+typedef void (APIENTRY *_glShaderSourceARB) (GLhandleARB, GLuint, const GLcharARB**, GLint *);
+typedef void (APIENTRY *_glCompileShaderARB) (GLhandleARB);
+typedef void (APIENTRY *_glGetObjectParameterivARB) (GLhandleARB, GLenum, int *);
+typedef void (APIENTRY *_glDeleteObjectARB) (GLhandleARB);
+typedef void (APIENTRY *_glGetInfoLogARB) (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
+typedef GLhandleARB (APIENTRY *_glCreateProgramObjectARB) ();
+typedef void (APIENTRY *_glAttachObjectARB) (GLhandleARB, GLhandleARB);
+typedef void (APIENTRY *_glDetachObjectARB) (GLhandleARB, GLhandleARB);
+typedef void (APIENTRY *_glLinkProgramARB) (GLhandleARB);
+typedef void (APIENTRY *_glUseProgramObjectARB) (GLhandleARB);
+typedef GLint (APIENTRY *_glGetUniformLocationARB) (GLhandleARB, const GLcharARB *);
+typedef void (APIENTRY *_glUniform1iARB) (GLint, GLint);
+typedef void (APIENTRY *_glUniform1fARB) (GLint, GLfloat);
+typedef void (APIENTRY *_glUniform4fARB) (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+typedef void (APIENTRY *_glUniformMatrix4fvARB) (GLint, GLuint, GLboolean, const GLfloat *);
+
+typedef void (APIENTRY *_glGenFramebuffersEXT) (GLsizei, GLuint *);
+typedef void (APIENTRY *_glGenRenderbuffersEXT) (GLsizei, GLuint *);
+typedef void (APIENTRY *_glBindRenderbufferEXT) (GLenum, GLuint);
+typedef void (APIENTRY *_glRenderbufferStorageEXT) (GLenum, GLenum, GLsizei, GLsizei);
+typedef void (APIENTRY *_glDeleteFramebuffersEXT) (GLsizei, const GLuint*);
+typedef void (APIENTRY *_glDeleteRenderbuffersEXT) (GLsizei, const GLuint*);
+typedef void (APIENTRY *_glBindFramebufferEXT) (GLenum, GLuint);
+typedef void (APIENTRY *_glFramebufferTexture2DEXT) (GLenum, GLenum, GLenum, GLuint, GLint);
+typedef void (APIENTRY *_glFramebufferRenderbufferEXT) (GLenum, GLenum, GLenum, GLuint);
+typedef GLenum (APIENTRY *_glCheckFramebufferStatusEXT) (GLenum);
+
+typedef void (APIENTRY *_glActiveTexture) (GLenum);
+typedef void (APIENTRY *_glTexImage3D) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+
+typedef void (APIENTRY *_glGenBuffers) (GLsizei, GLuint *);
+typedef void (APIENTRY *_glBindBuffer) (GLenum, GLuint);
+typedef void (APIENTRY *_glBufferData) (GLenum, GLsizeiptr, const GLvoid *, GLenum);
+typedef void (APIENTRY *_glDeleteBuffers) (GLsizei, const GLuint *);
+typedef void *(APIENTRY *_glMapBuffer) (GLenum, GLenum);
+typedef GLboolean (APIENTRY *_glUnmapBuffer) (GLenum);
+
+struct GLExtensionFunctions
+{
+ bool resolve(const QGLContext *context);
+
+ bool glslSupported();
+ bool fboSupported();
+ bool openGL15Supported(); // the rest: multi-texture, 3D-texture, vertex buffer objects
+
+ _glCreateShaderObjectARB CreateShaderObjectARB;
+ _glShaderSourceARB ShaderSourceARB;
+ _glCompileShaderARB CompileShaderARB;
+ _glGetObjectParameterivARB GetObjectParameterivARB;
+ _glDeleteObjectARB DeleteObjectARB;
+ _glGetInfoLogARB GetInfoLogARB;
+ _glCreateProgramObjectARB CreateProgramObjectARB;
+ _glAttachObjectARB AttachObjectARB;
+ _glDetachObjectARB DetachObjectARB;
+ _glLinkProgramARB LinkProgramARB;
+ _glUseProgramObjectARB UseProgramObjectARB;
+ _glGetUniformLocationARB GetUniformLocationARB;
+ _glUniform1iARB Uniform1iARB;
+ _glUniform1fARB Uniform1fARB;
+ _glUniform4fARB Uniform4fARB;
+ _glUniformMatrix4fvARB UniformMatrix4fvARB;
+
+ _glGenFramebuffersEXT GenFramebuffersEXT;
+ _glGenRenderbuffersEXT GenRenderbuffersEXT;
+ _glBindRenderbufferEXT BindRenderbufferEXT;
+ _glRenderbufferStorageEXT RenderbufferStorageEXT;
+ _glDeleteFramebuffersEXT DeleteFramebuffersEXT;
+ _glDeleteRenderbuffersEXT DeleteRenderbuffersEXT;
+ _glBindFramebufferEXT BindFramebufferEXT;
+ _glFramebufferTexture2DEXT FramebufferTexture2DEXT;
+ _glFramebufferRenderbufferEXT FramebufferRenderbufferEXT;
+ _glCheckFramebufferStatusEXT CheckFramebufferStatusEXT;
+
+ _glActiveTexture ActiveTexture;
+ _glTexImage3D TexImage3D;
+
+ _glGenBuffers GenBuffers;
+ _glBindBuffer BindBuffer;
+ _glBufferData BufferData;
+ _glDeleteBuffers DeleteBuffers;
+ _glMapBuffer MapBuffer;
+ _glUnmapBuffer UnmapBuffer;
+};
+
+inline GLExtensionFunctions &getGLExtensionFunctions()
+{
+ static GLExtensionFunctions funcs;
+ return funcs;
+}
+
+#define glCreateShaderObjectARB getGLExtensionFunctions().CreateShaderObjectARB
+#define glShaderSourceARB getGLExtensionFunctions().ShaderSourceARB
+#define glCompileShaderARB getGLExtensionFunctions().CompileShaderARB
+#define glGetObjectParameterivARB getGLExtensionFunctions().GetObjectParameterivARB
+#define glDeleteObjectARB getGLExtensionFunctions().DeleteObjectARB
+#define glGetInfoLogARB getGLExtensionFunctions().GetInfoLogARB
+#define glCreateProgramObjectARB getGLExtensionFunctions().CreateProgramObjectARB
+#define glAttachObjectARB getGLExtensionFunctions().AttachObjectARB
+#define glDetachObjectARB getGLExtensionFunctions().DetachObjectARB
+#define glLinkProgramARB getGLExtensionFunctions().LinkProgramARB
+#define glUseProgramObjectARB getGLExtensionFunctions().UseProgramObjectARB
+#define glGetUniformLocationARB getGLExtensionFunctions().GetUniformLocationARB
+#define glUniform1iARB getGLExtensionFunctions().Uniform1iARB
+#define glUniform1fARB getGLExtensionFunctions().Uniform1fARB
+#define glUniform4fARB getGLExtensionFunctions().Uniform4fARB
+#define glUniformMatrix4fvARB getGLExtensionFunctions().UniformMatrix4fvARB
+
+#define glGenFramebuffersEXT getGLExtensionFunctions().GenFramebuffersEXT
+#define glGenRenderbuffersEXT getGLExtensionFunctions().GenRenderbuffersEXT
+#define glBindRenderbufferEXT getGLExtensionFunctions().BindRenderbufferEXT
+#define glRenderbufferStorageEXT getGLExtensionFunctions().RenderbufferStorageEXT
+#define glDeleteFramebuffersEXT getGLExtensionFunctions().DeleteFramebuffersEXT
+#define glDeleteRenderbuffersEXT getGLExtensionFunctions().DeleteRenderbuffersEXT
+#define glBindFramebufferEXT getGLExtensionFunctions().BindFramebufferEXT
+#define glFramebufferTexture2DEXT getGLExtensionFunctions().FramebufferTexture2DEXT
+#define glFramebufferRenderbufferEXT getGLExtensionFunctions().FramebufferRenderbufferEXT
+#define glCheckFramebufferStatusEXT getGLExtensionFunctions().CheckFramebufferStatusEXT
+
+#define glActiveTexture getGLExtensionFunctions().ActiveTexture
+#define glTexImage3D getGLExtensionFunctions().TexImage3D
+
+#define glGenBuffers getGLExtensionFunctions().GenBuffers
+#define glBindBuffer getGLExtensionFunctions().BindBuffer
+#define glBufferData getGLExtensionFunctions().BufferData
+#define glDeleteBuffers getGLExtensionFunctions().DeleteBuffers
+#define glMapBuffer getGLExtensionFunctions().MapBuffer
+#define glUnmapBuffer getGLExtensionFunctions().UnmapBuffer
+
+#endif
diff --git a/demos/boxes/glshaders.cpp b/demos/boxes/glshaders.cpp
new file mode 100644
index 0000000..b6999a8
--- /dev/null
+++ b/demos/boxes/glshaders.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "glshaders.h"
+
+#define GLSHADERS_ASSERT_OPENGL(prefix, assertion, returnStatement) \
+if (m_failed || !(assertion)) { \
+ if (!m_failed) qCritical(prefix ": The necessary OpenGL functions are not available."); \
+ m_failed = true; \
+ returnStatement; \
+}
+
+
+GLShader::GLShader(const char *data, int size, GLenum shaderType)
+: m_compileError(false), m_failed(false)
+{
+ GLSHADERS_ASSERT_OPENGL("GLShader::GLShader",
+ glCreateShaderObjectARB && glShaderSourceARB && glCompileShaderARB && glGetObjectParameterivARB, return)
+
+ m_shader = glCreateShaderObjectARB(shaderType);
+
+ GLint glSize = size;
+ glShaderSourceARB(m_shader, 1, &data, &glSize);
+ glCompileShaderARB(m_shader);
+ int status;
+ glGetObjectParameterivARB(m_shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
+ m_compileError = (status != 1);
+}
+
+GLShader::GLShader(const QString& fileName, GLenum shaderType)
+ : m_compileError(false), m_failed(false)
+{
+ GLSHADERS_ASSERT_OPENGL("GLShader::GLShader",
+ glCreateShaderObjectARB && glShaderSourceARB && glCompileShaderARB && glGetObjectParameterivARB, return)
+
+ m_shader = glCreateShaderObjectARB(shaderType);
+
+ QFile file(fileName);
+ if (file.open(QIODevice::ReadOnly)) {
+ QByteArray bytes = file.readAll();
+ GLint size = file.size();
+ const char *p = bytes.data();
+ file.close();
+ glShaderSourceARB(m_shader, 1, &p, &size);
+ glCompileShaderARB(m_shader);
+ int status;
+ glGetObjectParameterivARB(m_shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
+ m_compileError = (status != 1);
+ } else {
+ m_compileError = true;
+ }
+}
+
+GLShader::~GLShader()
+{
+ GLSHADERS_ASSERT_OPENGL("GLShader::~GLShader", glDeleteObjectARB, return)
+
+ glDeleteObjectARB(m_shader);
+}
+
+QString GLShader::log()
+{
+ GLSHADERS_ASSERT_OPENGL("GLShader::log", glGetObjectParameterivARB
+ && glGetInfoLogARB, return QLatin1String("GLSL not supported."))
+
+ int length;
+ glGetObjectParameterivARB(m_shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
+ char *log = new char[length + 1];
+ GLsizei glLength = length;
+ glGetInfoLogARB(m_shader, glLength, &glLength, log);
+ log[glLength] = '\0';
+ QString result(log);
+ delete log;
+ return result;
+}
+
+GLVertexShader::GLVertexShader(const char *data, int size) : GLShader(data, size, GL_VERTEX_SHADER_ARB)
+{
+}
+
+GLVertexShader::GLVertexShader(const QString& fileName) : GLShader(fileName, GL_VERTEX_SHADER_ARB)
+{
+}
+
+GLFragmentShader::GLFragmentShader(const char *data, int size) : GLShader(data, size, GL_FRAGMENT_SHADER_ARB)
+{
+}
+
+GLFragmentShader::GLFragmentShader(const QString& fileName) : GLShader(fileName, GL_FRAGMENT_SHADER_ARB)
+{
+}
+
+GLProgram::GLProgram() : m_linked(false), m_linkError(false), m_failed(false)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::GLProgram", glCreateProgramObjectARB, return)
+
+ m_program = glCreateProgramObjectARB();
+}
+
+GLProgram::~GLProgram()
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::~GLProgram", glDeleteObjectARB, return)
+
+ glDeleteObjectARB(m_program);
+}
+
+void GLProgram::attach(const GLShader &shader)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::attach", glAttachObjectARB, return)
+
+ glAttachObjectARB(m_program, shader.m_shader);
+ m_linked = m_linkError = false;
+}
+
+void GLProgram::detach(const GLShader &shader)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::detach", glDetachObjectARB, return)
+
+ glDetachObjectARB(m_program, shader.m_shader);
+ m_linked = m_linkError = false;
+}
+
+bool GLProgram::failed()
+{
+ if (m_failed || m_linkError)
+ return true;
+
+ if (m_linked)
+ return false;
+
+ GLSHADERS_ASSERT_OPENGL("GLProgram::failed", glLinkProgramARB && glGetObjectParameterivARB, return true)
+
+ glLinkProgramARB(m_program);
+ int status;
+ glGetObjectParameterivARB(m_program, GL_OBJECT_LINK_STATUS_ARB, &status);
+ m_linkError = !(m_linked = (status == 1));
+ return m_linkError;
+}
+
+QString GLProgram::log()
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::log", glGetObjectParameterivARB && glGetInfoLogARB,
+ return QLatin1String("Failed."))
+
+ int length;
+ glGetObjectParameterivARB(m_program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
+ char *log = new char[length + 1];
+ GLsizei glLength = length;
+ glGetInfoLogARB(m_program, glLength, &glLength, log);
+ log[glLength] = '\0';
+ QString result(log);
+ delete log;
+ return result;
+}
+
+void GLProgram::bind()
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::bind", glUseProgramObjectARB, return)
+
+ if (!failed())
+ glUseProgramObjectARB(m_program);
+}
+
+void GLProgram::unbind()
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::bind", glUseProgramObjectARB, return)
+
+ glUseProgramObjectARB(0);
+}
+
+bool GLProgram::hasParameter(const QString& name)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::hasParameter", glGetUniformLocationARB, return false)
+
+ if (!failed()) {
+ QByteArray asciiName = name.toAscii();
+ return -1 != glGetUniformLocationARB(m_program, asciiName.data());
+ }
+ return false;
+}
+
+void GLProgram::setInt(const QString& name, int value)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::setInt", glGetUniformLocationARB && glUniform1iARB, return)
+
+ if (!failed()) {
+ QByteArray asciiName = name.toAscii();
+ int loc = glGetUniformLocationARB(m_program, asciiName.data());
+ glUniform1iARB(loc, value);
+ }
+}
+
+void GLProgram::setFloat(const QString& name, float value)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::setFloat", glGetUniformLocationARB && glUniform1fARB, return)
+
+ if (!failed()) {
+ QByteArray asciiName = name.toAscii();
+ int loc = glGetUniformLocationARB(m_program, asciiName.data());
+ glUniform1fARB(loc, value);
+ }
+}
+
+void GLProgram::setColor(const QString& name, QRgb value)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::setColor", glGetUniformLocationARB && glUniform4fARB, return)
+
+ //qDebug() << "Setting color" << name;
+ if (!failed()) {
+ QByteArray asciiName = name.toAscii();
+ int loc = glGetUniformLocationARB(m_program, asciiName.data());
+ //qDebug() << "Location of" << name << "is" << loc;
+ QColor color(value);
+ glUniform4fARB(loc, color.redF(), color.greenF(), color.blueF(), color.alphaF());
+ }
+}
+
+void GLProgram::setMatrix(const QString& name, const gfx::Matrix4x4f &mat)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::setMatrix", glGetUniformLocationARB && glUniformMatrix4fvARB, return)
+
+ if (!failed()) {
+ QByteArray asciiName = name.toAscii();
+ int loc = glGetUniformLocationARB(m_program, asciiName.data());
+ //qDebug() << "Location of" << name << "is" << loc;
+ glUniformMatrix4fvARB(loc, 1, GL_FALSE, mat.bits());
+ }
+} \ No newline at end of file
diff --git a/demos/boxes/glshaders.h b/demos/boxes/glshaders.h
new file mode 100644
index 0000000..2b6209a
--- /dev/null
+++ b/demos/boxes/glshaders.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GLSHADERS_H
+#define GLSHADERS_H
+
+//#include <GL/glew.h>
+#include "glextensions.h"
+
+#include <QtGui>
+#include <QtOpenGL>
+
+#include "vector.h"
+
+class GLShader
+{
+public:
+ friend class GLProgram;
+ virtual ~GLShader();
+ bool failed() const {return m_failed;}
+ QString log();
+protected:
+ GLShader(const char *data, int size, GLenum shaderType);
+ GLShader(const QString& fileName, GLenum shaderType);
+
+ GLhandleARB m_shader;
+ bool m_compileError;
+ bool m_failed;
+};
+
+class GLVertexShader : public GLShader
+{
+public:
+ GLVertexShader(const char *data, int size);
+ GLVertexShader(const QString& fileName);
+};
+
+class GLFragmentShader : public GLShader
+{
+public:
+ GLFragmentShader(const char *data, int size);
+ GLFragmentShader(const QString& fileName);
+};
+
+class GLProgram
+{
+public:
+ GLProgram();
+ ~GLProgram();
+ void attach(const GLShader &shader);
+ void detach(const GLShader &shader);
+ void bind();
+ void unbind();
+ bool failed();
+ QString log();
+ bool hasParameter(const QString& name);
+ // use program before setting values
+ void setInt(const QString& name, int value);
+ void setFloat(const QString& name, float value);
+ void setColor(const QString& name, QRgb value);
+ void setMatrix(const QString& name, const gfx::Matrix4x4f &mat);
+ // TODO: add a bunch of set-functions for different types.
+private:
+ GLhandleARB m_program;
+ bool m_linked;
+ bool m_linkError;
+ bool m_failed;
+};
+
+#endif
diff --git a/demos/boxes/gltrianglemesh.h b/demos/boxes/gltrianglemesh.h
new file mode 100644
index 0000000..c06ce90
--- /dev/null
+++ b/demos/boxes/gltrianglemesh.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GLTRIANGLEMESH_H
+#define GLTRIANGLEMESH_H
+
+//#include <GL/glew.h>
+#include "glextensions.h"
+
+#include <QtGui>
+#include <QtOpenGL>
+
+#include "glbuffers.h"
+
+template<class TVertex, class TIndex>
+class GLTriangleMesh
+{
+public:
+ GLTriangleMesh(int vertexCount, int indexCount) : m_vb(vertexCount), m_ib(indexCount)
+ {
+ }
+
+ virtual ~GLTriangleMesh()
+ {
+ }
+
+ virtual void draw()
+ {
+ if (failed())
+ return;
+
+ int type = GL_UNSIGNED_INT;
+ if (sizeof(TIndex) == sizeof(char)) type = GL_UNSIGNED_BYTE;
+ if (sizeof(TIndex) == sizeof(short)) type = GL_UNSIGNED_SHORT;
+
+ m_vb.bind();
+ m_ib.bind();
+ glDrawElements(GL_TRIANGLES, m_ib.length(), type, BUFFER_OFFSET(0));
+ m_vb.unbind();
+ m_ib.unbind();
+ }
+
+ bool failed()
+ {
+ return m_vb.failed() || m_ib.failed();
+ }
+protected:
+ GLVertexBuffer<TVertex> m_vb;
+ GLIndexBuffer<TIndex> m_ib;
+};
+
+
+#endif
diff --git a/demos/boxes/granite.fsh b/demos/boxes/granite.fsh
new file mode 100644
index 0000000..9b75d1d
--- /dev/null
+++ b/demos/boxes/granite.fsh
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform sampler3D noise;
+
+//const vec4 graniteColors[3] = {vec4(0.0, 0.0, 0.0, 1), vec4(0.30, 0.15, 0.10, 1), vec4(0.80, 0.70, 0.75, 1)};
+uniform vec4 graniteColors[3];
+
+float steep(float x)
+{
+ return clamp(5.0 * x - 2.0, 0.0, 1.0);
+}
+
+void main()
+{
+ vec2 turbulence = vec2(0, 0);
+ float scale = 1.0;
+ for (int i = 0; i < 4; ++i) {
+ turbulence += scale * (texture3D(noise, gl_TexCoord[1].xyz / scale).xy - 0.5);
+ scale *= 0.5;
+ }
+
+ vec3 N = normalize(normal);
+ // assume directional light
+
+ gl_MaterialParameters M = gl_FrontMaterial;
+
+ float NdotL = dot(N, lightDirection.xyz);
+ float RdotL = dot(reflect(normalize(position), N), lightDirection.xyz);
+
+ vec4 unlitColor = mix(graniteColors[1], mix(graniteColors[0], graniteColors[2], steep(0.5 + turbulence.y)), 4.0 * abs(turbulence.x));
+ gl_FragColor = (ambient + diffuse * max(NdotL, 0.0)) * unlitColor +
+ M.specular * specular * pow(max(RdotL, 0.0), M.shininess);
+}
diff --git a/demos/boxes/main.cpp b/demos/boxes/main.cpp
new file mode 100644
index 0000000..10bbde1
--- /dev/null
+++ b/demos/boxes/main.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#include <GL/glew.h>
+#include "glextensions.h"
+
+#include "scene.h"
+
+#include <QtGui>
+#include <QGLWidget>
+
+class GraphicsView : public QGraphicsView
+{
+public:
+ GraphicsView()
+ {
+ setWindowTitle(tr("Boxes"));
+ setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ //setRenderHints(QPainter::SmoothPixmapTransform);
+ }
+
+protected:
+ void resizeEvent(QResizeEvent *event) {
+ if (scene())
+ scene()->setSceneRect(QRect(QPoint(0, 0), event->size()));
+ QGraphicsView::resizeEvent(event);
+ }
+};
+
+inline bool matchString(const char *extensionString, const char *subString)
+{
+ int subStringLength = strlen(subString);
+ return (strncmp(extensionString, subString, subStringLength) == 0)
+ && ((extensionString[subStringLength] == ' ') || (extensionString[subStringLength] == '\0'));
+}
+
+bool necessaryExtensionsSupported()
+{
+ const char *extensionString = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
+ const char *p = extensionString;
+
+ const int GL_EXT_FBO = 1;
+ const int GL_ARB_VS = 2;
+ const int GL_ARB_FS = 4;
+ const int GL_ARB_SO = 8;
+ int extensions = 0;
+
+ while (*p) {
+ if (matchString(p, "GL_EXT_framebuffer_object"))
+ extensions |= GL_EXT_FBO;
+ else if (matchString(p, "GL_ARB_vertex_shader"))
+ extensions |= GL_ARB_VS;
+ else if (matchString(p, "GL_ARB_fragment_shader"))
+ extensions |= GL_ARB_FS;
+ else if (matchString(p, "GL_ARB_shader_objects"))
+ extensions |= GL_ARB_SO;
+ while ((*p != ' ') && (*p != '\0'))
+ ++p;
+ if (*p == ' ')
+ ++p;
+ }
+ return (extensions == 15);
+}
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+
+ if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_5) == 0) {
+ QMessageBox::critical(0, "OpenGL features missing",
+ "OpenGL version 1.5 or higher is required to run this demo.\n"
+ "The program will now exit.");
+ return -1;
+ }
+
+ int maxTextureSize = 1024;
+ QGLWidget *widget = new QGLWidget(QGLFormat(QGL::SampleBuffers));
+ widget->makeCurrent();
+
+ if (!necessaryExtensionsSupported()) {
+ QMessageBox::critical(0, "OpenGL features missing",
+ "The OpenGL extensions required to run this demo are missing.\n"
+ "The program will now exit.");
+ delete widget;
+ return -2;
+ }
+
+ // Check if all the necessary functions are resolved.
+ if (!getGLExtensionFunctions().resolve(widget->context())) {
+ QMessageBox::critical(0, "OpenGL features missing",
+ "Failed to resolve OpenGL functions required to run this demo.\n"
+ "The program will now exit.");
+ delete widget;
+ return -3;
+ }
+
+ // TODO: Make conditional for final release
+ QMessageBox::information(0, "For your information",
+ "This demo can be GPU and CPU intensive and may\n"
+ "work poorly or not at all on your system.");
+
+ GraphicsView view;
+ view.setViewport(widget);
+ view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
+ widget->makeCurrent(); // The current context must be set before calling Scene's constructor
+ view.setScene(new Scene(1024, 768, maxTextureSize));
+ view.show();
+
+ return app.exec();
+}
+
diff --git a/demos/boxes/marble.fsh b/demos/boxes/marble.fsh
new file mode 100644
index 0000000..62d3c9f
--- /dev/null
+++ b/demos/boxes/marble.fsh
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform sampler3D noise;
+
+//const vec4 marbleColors[2] = {vec4(0.9, 0.9, 0.9, 1), vec4(0.6, 0.5, 0.5, 1)};
+uniform vec4 marbleColors[2];
+
+void main()
+{
+ float turbulence = 0.0;
+ float scale = 1.0;
+ for (int i = 0; i < 4; ++i) {
+ turbulence += scale * (texture3D(noise, 0.125 * gl_TexCoord[1].xyz / scale).x - 0.5);
+ scale *= 0.5;
+ }
+
+ vec3 N = normalize(normal);
+ // assume directional light
+
+ gl_MaterialParameters M = gl_FrontMaterial;
+
+ float NdotL = dot(N, lightDirection.xyz);
+ float RdotL = dot(reflect(normalize(position), N), lightDirection.xyz);
+
+ vec4 unlitColor = mix(marbleColors[0], marbleColors[1], exp(-4.0 * abs(turbulence)));
+ gl_FragColor = (ambient + diffuse * max(NdotL, 0.0)) * unlitColor +
+ M.specular * specular * pow(max(RdotL, 0.0), M.shininess);
+}
diff --git a/demos/boxes/parameters.par b/demos/boxes/parameters.par
new file mode 100644
index 0000000..50e2073
--- /dev/null
+++ b/demos/boxes/parameters.par
@@ -0,0 +1,5 @@
+color basicColor ff0e3d0e
+color woodColors ff5e3d33 ffcc9966
+float woodTubulence 0.1
+color graniteColors ff000000 ff4d261a ffccb3bf
+color marbleColors ffe6e6e6 ff998080
diff --git a/demos/boxes/qt-logo.jpg b/demos/boxes/qt-logo.jpg
new file mode 100644
index 0000000..4014b46
--- /dev/null
+++ b/demos/boxes/qt-logo.jpg
Binary files differ
diff --git a/demos/boxes/qt-logo.png b/demos/boxes/qt-logo.png
new file mode 100644
index 0000000..7d3e97e
--- /dev/null
+++ b/demos/boxes/qt-logo.png
Binary files differ
diff --git a/demos/boxes/qtbox.cpp b/demos/boxes/qtbox.cpp
new file mode 100644
index 0000000..0607698
--- /dev/null
+++ b/demos/boxes/qtbox.cpp
@@ -0,0 +1,469 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtbox.h"
+
+const qreal ROTATE_SPEED_X = 30.0 / 1000.0;
+const qreal ROTATE_SPEED_Y = 20.0 / 1000.0;
+const qreal ROTATE_SPEED_Z = 40.0 / 1000.0;
+const int MAX_ITEM_SIZE = 512;
+const int MIN_ITEM_SIZE = 16;
+
+//============================================================================//
+// ItemBase //
+//============================================================================//
+
+ItemBase::ItemBase(int size, int x, int y) : m_size(size), m_isResizing(false)
+{
+ setFlag(QGraphicsItem::ItemIsMovable, true);
+ setFlag(QGraphicsItem::ItemIsSelectable, true);
+ setFlag(QGraphicsItem::ItemIsFocusable, true);
+ setAcceptHoverEvents(true);
+ setPos(x, y);
+ m_startTime = QTime::currentTime();
+}
+
+ItemBase::~ItemBase()
+{
+}
+
+QRectF ItemBase::boundingRect() const
+{
+ return QRectF(-m_size / 2, -m_size / 2, m_size, m_size);
+}
+
+void ItemBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
+{
+ if (option->state & QStyle::State_Selected) {
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ if (option->state & QStyle::State_HasFocus)
+ painter->setPen(Qt::yellow);
+ else
+ painter->setPen(Qt::white);
+ painter->drawRect(boundingRect());
+
+ painter->drawLine(m_size / 2 - 9, m_size / 2, m_size / 2, m_size / 2 - 9);
+ painter->drawLine(m_size / 2 - 6, m_size / 2, m_size / 2, m_size / 2 - 6);
+ painter->drawLine(m_size / 2 - 3, m_size / 2, m_size / 2, m_size / 2 - 3);
+
+ painter->setRenderHint(QPainter::Antialiasing, false);
+ }
+}
+
+void ItemBase::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
+{
+ if (!isSelected() && scene()) {
+ scene()->clearSelection();
+ setSelected(true);
+ }
+
+ QMenu menu;
+ QAction *delAction = menu.addAction("Delete");
+ QAction *newAction = menu.addAction("New");
+ QAction *growAction = menu.addAction("Grow");
+ QAction *shrinkAction = menu.addAction("Shrink");
+
+ QAction *selectedAction = menu.exec(event->screenPos());
+
+ if (selectedAction == delAction)
+ deleteSelectedItems(scene());
+ else if (selectedAction == newAction)
+ duplicateSelectedItems(scene());
+ else if (selectedAction == growAction)
+ growSelectedItems(scene());
+ else if (selectedAction == shrinkAction)
+ shrinkSelectedItems(scene());
+}
+
+void ItemBase::duplicateSelectedItems(QGraphicsScene *scene)
+{
+ if (!scene)
+ return;
+
+ QList<QGraphicsItem *> selected;
+ selected = scene->selectedItems();
+
+ foreach (QGraphicsItem *item, selected) {
+ ItemBase *itemBase = dynamic_cast<ItemBase *>(item);
+ if (itemBase)
+ scene->addItem(itemBase->createNew(itemBase->m_size, itemBase->pos().x() + itemBase->m_size, itemBase->pos().y()));
+ }
+}
+
+void ItemBase::deleteSelectedItems(QGraphicsScene *scene)
+{
+ if (!scene)
+ return;
+
+ QList<QGraphicsItem *> selected;
+ selected = scene->selectedItems();
+
+ foreach (QGraphicsItem *item, selected) {
+ ItemBase *itemBase = dynamic_cast<ItemBase *>(item);
+ if (itemBase)
+ delete itemBase;
+ }
+}
+
+void ItemBase::growSelectedItems(QGraphicsScene *scene)
+{
+ if (!scene)
+ return;
+
+ QList<QGraphicsItem *> selected;
+ selected = scene->selectedItems();
+
+ foreach (QGraphicsItem *item, selected) {
+ ItemBase *itemBase = dynamic_cast<ItemBase *>(item);
+ if (itemBase) {
+ itemBase->prepareGeometryChange();
+ itemBase->m_size *= 2;
+ if (itemBase->m_size > MAX_ITEM_SIZE)
+ itemBase->m_size = MAX_ITEM_SIZE;
+ }
+ }
+}
+
+void ItemBase::shrinkSelectedItems(QGraphicsScene *scene)
+{
+ if (!scene)
+ return;
+
+ QList<QGraphicsItem *> selected;
+ selected = scene->selectedItems();
+
+ foreach (QGraphicsItem *item, selected) {
+ ItemBase *itemBase = dynamic_cast<ItemBase *>(item);
+ if (itemBase) {
+ itemBase->prepareGeometryChange();
+ itemBase->m_size /= 2;
+ if (itemBase->m_size < MIN_ITEM_SIZE)
+ itemBase->m_size = MIN_ITEM_SIZE;
+ }
+ }
+}
+
+void ItemBase::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (m_isResizing) {
+ int dx = int(2.0 * event->pos().x());
+ int dy = int(2.0 * event->pos().y());
+ prepareGeometryChange();
+ m_size = (dx > dy ? dx : dy);
+ if (m_size < MIN_ITEM_SIZE)
+ m_size = MIN_ITEM_SIZE;
+ else if (m_size > MAX_ITEM_SIZE)
+ m_size = MAX_ITEM_SIZE;
+ } else {
+ QGraphicsItem::mouseMoveEvent(event);
+ }
+}
+
+void ItemBase::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ if (m_isResizing || (isInResizeArea(event->pos()) && isSelected()))
+ setCursor(Qt::SizeFDiagCursor);
+ else
+ setCursor(Qt::ArrowCursor);
+ QGraphicsItem::hoverMoveEvent(event);
+}
+
+void ItemBase::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ static qreal z = 0.0;
+ setZValue(z += 1.0);
+ if (event->button() == Qt::LeftButton && isInResizeArea(event->pos())) {
+ m_isResizing = true;
+ } else {
+ QGraphicsItem::mousePressEvent(event);
+ }
+}
+
+void ItemBase::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton && m_isResizing) {
+ m_isResizing = false;
+ } else {
+ QGraphicsItem::mouseReleaseEvent(event);
+ }
+}
+
+void ItemBase::keyPressEvent(QKeyEvent *event)
+{
+ switch (event->key()) {
+ case Qt::Key_Delete:
+ deleteSelectedItems(scene());
+ break;
+ case Qt::Key_Insert:
+ duplicateSelectedItems(scene());
+ break;
+ case Qt::Key_Plus:
+ growSelectedItems(scene());
+ break;
+ case Qt::Key_Minus:
+ shrinkSelectedItems(scene());
+ break;
+ default:
+ QGraphicsItem::keyPressEvent(event);
+ break;
+ }
+}
+
+void ItemBase::wheelEvent(QGraphicsSceneWheelEvent *event)
+{
+ prepareGeometryChange();
+ m_size = int(m_size * exp(-event->delta() / 600.0));
+ if (m_size > MAX_ITEM_SIZE)
+ m_size = MAX_ITEM_SIZE;
+ else if (m_size < MIN_ITEM_SIZE)
+ m_size = MIN_ITEM_SIZE;
+}
+
+bool ItemBase::isInResizeArea(const QPointF &pos)
+{
+ return (-pos.y() < pos.x() - m_size + 9);
+}
+
+//============================================================================//
+// QtBox //
+//============================================================================//
+
+QtBox::QtBox(int size, int x, int y) : ItemBase(size, x, y), m_texture(0)
+{
+ for (int i = 0; i < 8; ++i) {
+ m_vertices[i][0] = (i & 1 ? 0.5f : -0.5f);
+ m_vertices[i][1] = (i & 2 ? 0.5f : -0.5f);
+ m_vertices[i][2] = (i & 4 ? 0.5f : -0.5f);
+ }
+ for (int i = 0; i < 4; ++i) {
+ m_texCoords[i][0] = (i & 1 ? 1.0f : 0.0f);
+ m_texCoords[i][1] = (i & 2 ? 1.0f : 0.0f);
+ }
+ memset(m_normals, 0, sizeof(m_normals));
+ for (int i = 0; i < 3; ++i) {
+ m_normals[2 * i + 0][i] = -1.0f;
+ m_normals[2 * i + 1][i] = 1.0f;
+ }
+}
+
+QtBox::~QtBox()
+{
+ if (m_texture)
+ delete m_texture;
+}
+
+ItemBase *QtBox::createNew(int size, int x, int y)
+{
+ return new QtBox(size, x, y);
+}
+
+void QtBox::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ QRectF rect = boundingRect().translated(pos());
+ float width = float(painter->device()->width());
+ float height = float(painter->device()->height());
+
+ float left = 2.0f * float(rect.left()) / width - 1.0f;
+ float right = 2.0f * float(rect.right()) / width - 1.0f;
+ float top = 1.0f - 2.0f * float(rect.top()) / height;
+ float bottom = 1.0f - 2.0f * float(rect.bottom()) / height;
+ float moveToRectMatrix[] = {
+ 0.5f * (right - left), 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.5f * (bottom - top), 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.5f * (right + left), 0.5f * (bottom + top), 0.0f, 1.0f
+ };
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(moveToRectMatrix);
+ gluPerspective(60.0, 1.0, 0.01, 10.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ //glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_COLOR_MATERIAL);
+ glEnable(GL_NORMALIZE);
+
+ if(m_texture == 0)
+ m_texture = new GLTexture2D(":/res/boxes/qt-logo.jpg", 64, 64);
+ m_texture->bind();
+ glEnable(GL_TEXTURE_2D);
+
+ glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
+ float lightColour[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ float lightDir[] = {0.0f, 0.0f, 1.0f, 0.0f};
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColour);
+ glLightfv(GL_LIGHT0, GL_POSITION, lightDir);
+ glEnable(GL_LIGHT0);
+
+ glTranslatef(0.0f, 0.0f, -1.5f);
+ glRotatef(ROTATE_SPEED_X * m_startTime.msecsTo(QTime::currentTime()), 1.0f, 0.0f, 0.0f);
+ glRotatef(ROTATE_SPEED_Y * m_startTime.msecsTo(QTime::currentTime()), 0.0f, 1.0f, 0.0f);
+ glRotatef(ROTATE_SPEED_Z * m_startTime.msecsTo(QTime::currentTime()), 0.0f, 0.0f, 1.0f);
+ int dt = m_startTime.msecsTo(QTime::currentTime());
+ if (dt < 500)
+ glScalef(dt / 500.0f, dt / 500.0f, dt / 500.0f);
+
+ for (int dir = 0; dir < 3; ++dir) {
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0);
+
+ glBegin(GL_TRIANGLE_STRIP);
+ glNormal3fv(m_normals[2 * dir + 0].bits());
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ glTexCoord2fv(m_texCoords[(j << 1) | i].bits());
+ glVertex3fv(m_vertices[(i << ((dir + 2) % 3)) | (j << ((dir + 1) % 3))].bits());
+ }
+ }
+ glEnd();
+
+ glBegin(GL_TRIANGLE_STRIP);
+ glNormal3fv(m_normals[2 * dir + 1].bits());
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ glTexCoord2fv(m_texCoords[(j << 1) | i].bits());
+ glVertex3fv(m_vertices[(1 << dir) | (i << ((dir + 1) % 3)) | (j << ((dir + 2) % 3))].bits());
+ }
+ }
+ glEnd();
+ }
+ m_texture->unbind();
+
+ //glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_LIGHT0);
+ glDisable(GL_NORMALIZE);
+
+ glPopMatrix();
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+
+ ItemBase::paint(painter, option, widget);
+}
+
+//============================================================================//
+// CircleItem //
+//============================================================================//
+
+CircleItem::CircleItem(int size, int x, int y) : ItemBase(size, x, y)
+{
+ m_color = QColor::fromHsv(rand() % 360, 255, 255);
+}
+
+void CircleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ int dt = m_startTime.msecsTo(QTime::currentTime());
+
+ qreal r0 = 0.5 * m_size * (1.0 - exp(-0.001 * ((dt + 3800) % 4000)));
+ qreal r1 = 0.5 * m_size * (1.0 - exp(-0.001 * ((dt + 0) % 4000)));
+ qreal r2 = 0.5 * m_size * (1.0 - exp(-0.001 * ((dt + 1800) % 4000)));
+ qreal r3 = 0.5 * m_size * (1.0 - exp(-0.001 * ((dt + 2000) % 4000)));
+
+ if (r0 > r1)
+ r0 = 0.0;
+ if (r2 > r3)
+ r2 = 0.0;
+
+ QPainterPath path;
+ path.moveTo(r1, 0.0);
+ path.arcTo(-r1, -r1, 2 * r1, 2 * r1, 0.0, 360.0);
+ path.lineTo(r0, 0.0);
+ path.arcTo(-r0, -r0, 2 * r0, 2 * r0, 0.0, -360.0);
+ path.closeSubpath();
+ path.moveTo(r3, 0.0);
+ path.arcTo(-r3, -r3, 2 * r3, 2 * r3, 0.0, 360.0);
+ path.lineTo(r0, 0.0);
+ path.arcTo(-r2, -r2, 2 * r2, 2 * r2, 0.0, -360.0);
+ path.closeSubpath();
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ painter->setBrush(QBrush(m_color));
+ painter->setPen(Qt::NoPen);
+ painter->drawPath(path);
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(Qt::SolidLine);
+ painter->setRenderHint(QPainter::Antialiasing, false);
+
+ ItemBase::paint(painter, option, widget);
+}
+
+ItemBase *CircleItem::createNew(int size, int x, int y)
+{
+ return new CircleItem(size, x, y);
+}
+
+//============================================================================//
+// SquareItem //
+//============================================================================//
+
+SquareItem::SquareItem(int size, int x, int y) : ItemBase(size, x, y)
+{
+ m_image = QPixmap(":/res/boxes/square.jpg");
+}
+
+void SquareItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ int dt = m_startTime.msecsTo(QTime::currentTime());
+ QTransform oldTransform = painter->worldTransform();
+ int dtMod = dt % 2000;
+ qreal amp = 0.002 * (dtMod < 1000 ? dtMod : 2000 - dtMod) - 1.0;
+
+ qreal scale = 0.6 + 0.2 * amp * amp;
+ painter->setWorldTransform(QTransform().rotate(15.0 * amp).scale(scale, scale), true);
+
+ painter->drawPixmap(-m_size / 2, -m_size / 2, m_size, m_size, m_image);
+
+ painter->setWorldTransform(oldTransform, false);
+ ItemBase::paint(painter, option, widget);
+}
+
+ItemBase *SquareItem::createNew(int size, int x, int y)
+{
+ return new SquareItem(size, x, y);
+}
diff --git a/demos/boxes/qtbox.h b/demos/boxes/qtbox.h
new file mode 100644
index 0000000..aae8256
--- /dev/null
+++ b/demos/boxes/qtbox.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTBOX_H
+#define QTBOX_H
+
+#include <QtGui>
+
+#include "vector.h"
+#include "glbuffers.h"
+
+class ItemBase : public QObject, public QGraphicsItem
+{
+ Q_OBJECT
+public:
+ ItemBase(int size, int x, int y);
+ virtual ~ItemBase();
+ virtual QRectF boundingRect() const;
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+protected:
+ virtual ItemBase *createNew(int size, int x, int y) = 0;
+ virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void keyPressEvent(QKeyEvent *event);
+ virtual void wheelEvent(QGraphicsSceneWheelEvent *event);
+ bool isInResizeArea(const QPointF &pos);
+
+ static void duplicateSelectedItems(QGraphicsScene *scene);
+ static void deleteSelectedItems(QGraphicsScene *scene);
+ static void growSelectedItems(QGraphicsScene *scene);
+ static void shrinkSelectedItems(QGraphicsScene *scene);
+
+ int m_size;
+ QTime m_startTime;
+ bool m_isResizing;
+};
+
+class QtBox : public ItemBase
+{
+public:
+ QtBox(int size, int x, int y);
+ virtual ~QtBox();
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+protected:
+ virtual ItemBase *createNew(int size, int x, int y);
+private:
+ gfx::Vector3f m_vertices[8];
+ gfx::Vector2f m_texCoords[4];
+ gfx::Vector3f m_normals[6];
+ GLTexture *m_texture;
+};
+
+class CircleItem : public ItemBase
+{
+public:
+ CircleItem(int size, int x, int y);
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+protected:
+ virtual ItemBase *createNew(int size, int x, int y);
+
+ QColor m_color;
+};
+
+class SquareItem : public ItemBase
+{
+public:
+ SquareItem(int size, int x, int y);
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+protected:
+ virtual ItemBase *createNew(int size, int x, int y);
+
+ QPixmap m_image;
+};
+
+#endif
diff --git a/demos/boxes/reflection.fsh b/demos/boxes/reflection.fsh
new file mode 100644
index 0000000..d5807ee
--- /dev/null
+++ b/demos/boxes/reflection.fsh
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform samplerCube env;
+uniform mat4 view;
+
+void main()
+{
+ vec3 N = normalize(normal);
+ vec3 R = 2.0 * dot(-position, N) * N + position;
+ gl_FragColor = textureCube(env, R * mat3(view[0].xyz, view[1].xyz, view[2].xyz));
+}
diff --git a/demos/boxes/refraction.fsh b/demos/boxes/refraction.fsh
new file mode 100644
index 0000000..f91c24d
--- /dev/null
+++ b/demos/boxes/refraction.fsh
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform samplerCube env;
+uniform mat4 view;
+
+// Arrays don't work here on glsl < 120, apparently.
+//const float coeffs[6] = float[6](1.0/2.0, 1.0/2.1, 1.0/2.2, 1.0/2.3, 1.0/2.4, 1.0/2.5);
+float coeffs(int i)
+{
+ return 1.0 / (2.0 + 0.1 * float(i));
+}
+
+void main()
+{
+ vec3 N = normalize(normal);
+ vec3 I = -normalize(position);
+ float IdotN = dot(I, N);
+ float scales[6];
+ vec3 C[6];
+ for (int i = 0; i < 6; ++i) {
+ scales[i] = (IdotN - sqrt(1.0 - coeffs(i) + coeffs(i) * (IdotN * IdotN)));
+ C[i] = textureCube(env, (-I + coeffs(i) * N) * mat3(view[0].xyz, view[1].xyz, view[2].xyz)).xyz;
+ }
+
+ gl_FragColor = 0.25 * vec4(C[5].x + 2.0*C[0].x + C[1].x, C[1].y + 2.0*C[2].y + C[3].y,
+ C[3].z + 2.0*C[4].z + C[5].z, 4.0);
+}
diff --git a/demos/boxes/roundedbox.cpp b/demos/boxes/roundedbox.cpp
new file mode 100644
index 0000000..f238da2
--- /dev/null
+++ b/demos/boxes/roundedbox.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "roundedbox.h"
+
+//============================================================================//
+// P3T2N3Vertex //
+//============================================================================//
+
+VertexDescription P3T2N3Vertex::description[] = {
+ {VertexDescription::Position, GL_FLOAT, SIZE_OF_MEMBER(P3T2N3Vertex, position) / sizeof(float), offsetof(P3T2N3Vertex, position), 0},
+ {VertexDescription::TexCoord, GL_FLOAT, SIZE_OF_MEMBER(P3T2N3Vertex, texCoord) / sizeof(float), offsetof(P3T2N3Vertex, texCoord), 0},
+ {VertexDescription::Normal, GL_FLOAT, SIZE_OF_MEMBER(P3T2N3Vertex, normal) / sizeof(float), offsetof(P3T2N3Vertex, normal), 0},
+ {VertexDescription::Null, 0, 0, 0, 0},
+};
+
+//============================================================================//
+// GLRoundedBox //
+//============================================================================//
+
+float lerp(float a, float b, float t)
+{
+ return a * (1.0f - t) + b * t;
+}
+
+GLRoundedBox::GLRoundedBox(float r, float scale, int n)
+ : GLTriangleMesh<P3T2N3Vertex, unsigned short>((n+2)*(n+3)*4, (n+1)*(n+1)*24+36+72*(n+1))
+{
+ int vidx = 0, iidx = 0;
+ int vertexCountPerCorner = (n + 2) * (n + 3) / 2;
+
+ P3T2N3Vertex *vp = m_vb.lock();
+ unsigned short *ip = m_ib.lock();
+
+ if (!vp || !ip) {
+ qWarning("GLRoundedBox::GLRoundedBox: Failed to lock vertex buffer and/or index buffer.");
+ m_ib.unlock();
+ m_vb.unlock();
+ return;
+ }
+
+ for (int corner = 0; corner < 8; ++corner) {
+ gfx::Vector3f centre;
+ centre[0] = (corner & 1 ? 1.0f : -1.0f);
+ centre[1] = (corner & 2 ? 1.0f : -1.0f);
+ centre[2] = (corner & 4 ? 1.0f : -1.0f);
+ int winding = (corner & 1) ^ ((corner >> 1) & 1) ^ (corner >> 2);
+ int offsX = ((corner ^ 1) - corner) * vertexCountPerCorner;
+ int offsY = ((corner ^ 2) - corner) * vertexCountPerCorner;
+ int offsZ = ((corner ^ 4) - corner) * vertexCountPerCorner;
+
+ // Face polygons
+ if (winding) {
+ ip[iidx++] = vidx;
+ ip[iidx++] = vidx + offsX;
+ ip[iidx++] = vidx + offsY;
+
+ ip[iidx++] = vidx + vertexCountPerCorner - n - 2;
+ ip[iidx++] = vidx + vertexCountPerCorner - n - 2 + offsY;
+ ip[iidx++] = vidx + vertexCountPerCorner - n - 2 + offsZ;
+
+ ip[iidx++] = vidx + vertexCountPerCorner - 1;
+ ip[iidx++] = vidx + vertexCountPerCorner - 1 + offsZ;
+ ip[iidx++] = vidx + vertexCountPerCorner - 1 + offsX;
+ }
+
+ for (int i = 0; i < n + 2; ++i) {
+
+ // Edge polygons
+ if (winding && i < n + 1) {
+ ip[iidx++] = vidx + i + 1;
+ ip[iidx++] = vidx;
+ ip[iidx++] = vidx + offsY + i + 1;
+ ip[iidx++] = vidx + offsY;
+ ip[iidx++] = vidx + offsY + i + 1;
+ ip[iidx++] = vidx;
+
+ ip[iidx++] = vidx + i;
+ ip[iidx++] = vidx + 2 * i + 2;
+ ip[iidx++] = vidx + i + offsX;
+ ip[iidx++] = vidx + 2 * i + offsX + 2;
+ ip[iidx++] = vidx + i + offsX;
+ ip[iidx++] = vidx + 2 * i + 2;
+
+ ip[iidx++] = (corner + 1) * vertexCountPerCorner - 1 - i;
+ ip[iidx++] = (corner + 1) * vertexCountPerCorner - 2 - i;
+ ip[iidx++] = (corner + 1) * vertexCountPerCorner - 1 - i + offsZ;
+ ip[iidx++] = (corner + 1) * vertexCountPerCorner - 2 - i + offsZ;
+ ip[iidx++] = (corner + 1) * vertexCountPerCorner - 1 - i + offsZ;
+ ip[iidx++] = (corner + 1) * vertexCountPerCorner - 2 - i;
+ }
+
+ for (int j = 0; j <= i; ++j) {
+ gfx::Vector3f normal = gfx::Vector3f::vector(i - j, j, n + 1 - i).normalized();
+ gfx::Vector3f pos = centre * (0.5f - r + r * normal);
+
+ vp[vidx].position = scale * pos;
+ vp[vidx].normal = centre * normal;
+ vp[vidx].texCoord = gfx::Vector2f::vector(pos[0], pos[1]) + 0.5f;
+
+ // Corner polygons
+ if (i < n + 1) {
+ ip[iidx++] = vidx;
+ ip[iidx++] = vidx + i + 2 - winding;
+ ip[iidx++] = vidx + i + 1 + winding;
+ }
+ if (i < n) {
+ ip[iidx++] = vidx + i + 1 + winding;
+ ip[iidx++] = vidx + i + 2 - winding;
+ ip[iidx++] = vidx + 2 * i + 4;
+ }
+
+ ++vidx;
+ }
+ }
+
+ }
+
+ m_ib.unlock();
+ m_vb.unlock();
+}
+
diff --git a/demos/boxes/roundedbox.h b/demos/boxes/roundedbox.h
new file mode 100644
index 0000000..b934ade
--- /dev/null
+++ b/demos/boxes/roundedbox.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ROUNDEDBOX_H
+#define ROUNDEDBOX_H
+
+//#include <GL/glew.h>
+#include "glextensions.h"
+
+#include <QtGui>
+#include <QtOpenGL>
+
+#include "gltrianglemesh.h"
+#include "vector.h"
+#include "glbuffers.h"
+
+struct P3T2N3Vertex
+{
+ gfx::Vector3f position;
+ gfx::Vector2f texCoord;
+ gfx::Vector3f normal;
+ static VertexDescription description[];
+};
+
+class GLRoundedBox : public GLTriangleMesh<P3T2N3Vertex, unsigned short>
+{
+public:
+ // 0 < r < 0.5, 0 <= n <= 125
+ GLRoundedBox(float r = 0.25f, float scale = 1.0f, int n = 10);
+};
+
+
+#endif
diff --git a/demos/boxes/scene.cpp b/demos/boxes/scene.cpp
new file mode 100644
index 0000000..1040e17
--- /dev/null
+++ b/demos/boxes/scene.cpp
@@ -0,0 +1,1057 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "scene.h"
+
+#include "3rdparty/fbm.h"
+
+void checkGLErrors(const QString& prefix)
+{
+ switch (glGetError()) {
+ case GL_NO_ERROR:
+ //qDebug() << prefix << tr("No error.");
+ break;
+ case GL_INVALID_ENUM:
+ qDebug() << prefix << QObject::tr("Invalid enum.");
+ break;
+ case GL_INVALID_VALUE:
+ qDebug() << prefix << QObject::tr("Invalid value.");
+ break;
+ case GL_INVALID_OPERATION:
+ qDebug() << prefix << QObject::tr("Invalid operation.");
+ break;
+ case GL_STACK_OVERFLOW:
+ qDebug() << prefix << QObject::tr("Stack overflow.");
+ break;
+ case GL_STACK_UNDERFLOW:
+ qDebug() << prefix << QObject::tr("Stack underflow.");
+ break;
+ case GL_OUT_OF_MEMORY:
+ qDebug() << prefix << QObject::tr("Out of memory.");
+ break;
+ default:
+ qDebug() << prefix << QObject::tr("Unknown error.");
+ break;
+ }
+}
+
+//============================================================================//
+// ColorEdit //
+//============================================================================//
+
+ColorEdit::ColorEdit(QRgb initialColor, int id)
+ : m_color(initialColor), m_id(id)
+{
+ QHBoxLayout *layout = new QHBoxLayout;
+ setLayout(layout);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ m_lineEdit = new QLineEdit(QString::number(m_color, 16));
+ layout->addWidget(m_lineEdit);
+
+ m_button = new QFrame;
+ QPalette palette = m_button->palette();
+ palette.setColor(QPalette::Window, QColor(m_color));
+ m_button->setPalette(palette);
+ m_button->setAutoFillBackground(true);
+ m_button->setMinimumSize(32, 0);
+ m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ m_button->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
+ layout->addWidget(m_button);
+
+ connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(editDone()));
+}
+
+void ColorEdit::editDone()
+{
+ bool ok;
+ QRgb newColor = m_lineEdit->text().toUInt(&ok, 16);
+ if (ok)
+ setColor(newColor);
+}
+
+void ColorEdit::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton) {
+ QColor color(m_color);
+ QColorDialog dialog(color, 0);
+ dialog.setOption(QColorDialog::ShowAlphaChannel, true);
+// The ifdef block is a workaround for the beta, TODO: remove when bug 238525 is fixed
+#ifdef Q_WS_MAC
+ dialog.setOption(QColorDialog::DontUseNativeDialog, true);
+#endif
+ dialog.move(280, 120);
+ if (dialog.exec() == QDialog::Rejected)
+ return;
+ QRgb newColor = dialog.selectedColor().rgba();
+ if (newColor == m_color)
+ return;
+ setColor(newColor);
+ }
+}
+
+void ColorEdit::setColor(QRgb color)
+{
+ m_color = color;
+ m_lineEdit->setText(QString::number(m_color, 16)); // "Clean up" text
+ QPalette palette = m_button->palette();
+ palette.setColor(QPalette::Window, QColor(m_color));
+ m_button->setPalette(palette);
+ emit colorChanged(m_color, m_id);
+}
+
+//============================================================================//
+// FloatEdit //
+//============================================================================//
+
+FloatEdit::FloatEdit(float initialValue, int id)
+ : m_value(initialValue), m_id(id)
+{
+ QHBoxLayout *layout = new QHBoxLayout;
+ setLayout(layout);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ m_lineEdit = new QLineEdit(QString::number(m_value));
+ layout->addWidget(m_lineEdit);
+
+ connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(editDone()));
+}
+
+void FloatEdit::editDone()
+{
+ bool ok;
+ float newValue = m_lineEdit->text().toFloat(&ok);
+ if (ok) {
+ m_value = newValue;
+ m_lineEdit->setText(QString::number(m_value)); // "Clean up" text
+ emit valueChanged(m_value, m_id);
+ }
+}
+
+//============================================================================//
+// TwoSidedGraphicsWidget //
+//============================================================================//
+
+TwoSidedGraphicsWidget::TwoSidedGraphicsWidget(QGraphicsScene *scene)
+ : QObject(scene)
+ , m_current(0)
+ , m_angle(0)
+ , m_delta(0)
+{
+ for (int i = 0; i < 2; ++i)
+ m_proxyWidgets[i] = 0;
+}
+
+void TwoSidedGraphicsWidget::setWidget(int index, QWidget *widget)
+{
+ if (index < 0 || index >= 2)
+ {
+ qWarning("TwoSidedGraphicsWidget::setWidget: Index out of bounds, index == %d", index);
+ return;
+ }
+
+ GraphicsWidget *proxy = new GraphicsWidget;
+ proxy->setWidget(widget);
+
+ if (m_proxyWidgets[index])
+ delete m_proxyWidgets[index];
+ m_proxyWidgets[index] = proxy;
+
+ proxy->setCacheMode(QGraphicsItem::ItemCoordinateCache);
+ proxy->setZValue(1e30); // Make sure the dialog is drawn on top of all other (OpenGL) items
+
+ if (index != m_current)
+ proxy->setVisible(false);
+
+ qobject_cast<QGraphicsScene *>(parent())->addItem(proxy);
+}
+
+QWidget *TwoSidedGraphicsWidget::widget(int index)
+{
+ if (index < 0 || index >= 2)
+ {
+ qWarning("TwoSidedGraphicsWidget::widget: Index out of bounds, index == %d", index);
+ return 0;
+ }
+ return m_proxyWidgets[index]->widget();
+}
+
+void TwoSidedGraphicsWidget::flip()
+{
+ m_delta = (m_current == 0 ? 9 : -9);
+ animateFlip();
+}
+
+void TwoSidedGraphicsWidget::animateFlip()
+{
+ m_angle += m_delta;
+ if (m_angle == 90) {
+ int old = m_current;
+ m_current ^= 1;
+ m_proxyWidgets[old]->setVisible(false);
+ m_proxyWidgets[m_current]->setVisible(true);
+ m_proxyWidgets[m_current]->setGeometry(m_proxyWidgets[old]->geometry());
+ }
+
+ QRectF r = m_proxyWidgets[m_current]->boundingRect();
+ m_proxyWidgets[m_current]->setTransform(QTransform()
+ .translate(r.width() / 2, r.height() / 2)
+ .rotate(m_angle - 180 * m_current, Qt::YAxis)
+ .translate(-r.width() / 2, -r.height() / 2));
+
+ if ((m_current == 0 && m_angle > 0) || (m_current == 1 && m_angle < 180))
+ QTimer::singleShot(25, this, SLOT(animateFlip()));
+}
+
+QVariant GraphicsWidget::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ if (change == ItemPositionChange && scene()) {
+ QRectF rect = boundingRect();
+ QPointF pos = value.toPointF();
+ QRectF sceneRect = scene()->sceneRect();
+ if (pos.x() + rect.left() < sceneRect.left())
+ pos.setX(sceneRect.left() - rect.left());
+ else if (pos.x() + rect.right() >= sceneRect.right())
+ pos.setX(sceneRect.right() - rect.right());
+ if (pos.y() + rect.top() < sceneRect.top())
+ pos.setY(sceneRect.top() - rect.top());
+ else if (pos.y() + rect.bottom() >= sceneRect.bottom())
+ pos.setY(sceneRect.bottom() - rect.bottom());
+ return pos;
+ }
+ return QGraphicsProxyWidget::itemChange(change, value);
+}
+
+void GraphicsWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
+{
+ setCacheMode(QGraphicsItem::NoCache);
+ setCacheMode(QGraphicsItem::ItemCoordinateCache);
+ QGraphicsProxyWidget::resizeEvent(event);
+}
+
+void GraphicsWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ painter->setRenderHint(QPainter::Antialiasing, false);
+ QGraphicsProxyWidget::paint(painter, option, widget);
+ //painter->setRenderHint(QPainter::Antialiasing, true);
+}
+
+//============================================================================//
+// RenderOptionsDialog //
+//============================================================================//
+
+RenderOptionsDialog::RenderOptionsDialog()
+ : QDialog(0, Qt::CustomizeWindowHint | Qt::WindowTitleHint)
+{
+ setWindowOpacity(0.75);
+ setWindowTitle(tr("Options (double click to flip)"));
+ QGridLayout *layout = new QGridLayout;
+ setLayout(layout);
+ layout->setColumnStretch(1, 1);
+
+ int row = 0;
+
+ QCheckBox *check = new QCheckBox(tr("Dynamic cube map"));
+ check->setCheckState(Qt::Unchecked);
+ // Dynamic cube maps are only enabled when multi-texturing and render to texture are available.
+ check->setEnabled(glActiveTexture && glGenFramebuffersEXT);
+ connect(check, SIGNAL(stateChanged(int)), this, SIGNAL(dynamicCubemapToggled(int)));
+ layout->addWidget(check, 0, 0, 1, 2);
+ ++row;
+
+ QPalette palette;
+
+ // Load all .par files
+ // .par files have a simple syntax for specifying user adjustable uniform variables.
+ QSet<QByteArray> uniforms;
+ QList<QString> filter = QStringList("*.par");
+ QList<QFileInfo> files = QDir(":/res/boxes/").entryInfoList(filter, QDir::Files | QDir::Readable);
+
+ foreach (QFileInfo fileInfo, files) {
+ QFile file(fileInfo.absoluteFilePath());
+ if (file.open(QIODevice::ReadOnly)) {
+ while (!file.atEnd()) {
+ QList<QByteArray> tokens = file.readLine().simplified().split(' ');
+ QList<QByteArray>::const_iterator it = tokens.begin();
+ if (it == tokens.end())
+ continue;
+ QByteArray type = *it;
+ if (++it == tokens.end())
+ continue;
+ QByteArray name = *it;
+ bool singleElement = (tokens.size() == 3); // type, name and one value
+ char counter[10] = "000000000";
+ int counterPos = 8; // position of last digit
+ while (++it != tokens.end()) {
+ m_parameterNames << name;
+ if (!singleElement) {
+ m_parameterNames.back() += "[";
+ m_parameterNames.back() += counter + counterPos;
+ m_parameterNames.back() += "]";
+ int j = 8; // position of last digit
+ ++counter[j];
+ while (j > 0 && counter[j] > '9') {
+ counter[j] = '0';
+ ++counter[--j];
+ }
+ if (j < counterPos)
+ counterPos = j;
+ }
+
+ if (type == "color") {
+ layout->addWidget(new QLabel(m_parameterNames.back()));
+ bool ok;
+ ColorEdit *colorEdit = new ColorEdit(it->toUInt(&ok, 16), m_parameterNames.size() - 1);
+ m_parameterEdits << colorEdit;
+ layout->addWidget(colorEdit);
+ connect(colorEdit, SIGNAL(colorChanged(QRgb, int)), this, SLOT(setColorParameter(QRgb, int)));
+ ++row;
+ } else if (type == "float") {
+ layout->addWidget(new QLabel(m_parameterNames.back()));
+ bool ok;
+ FloatEdit *floatEdit = new FloatEdit(it->toFloat(&ok), m_parameterNames.size() - 1);
+ m_parameterEdits << floatEdit;
+ layout->addWidget(floatEdit);
+ connect(floatEdit, SIGNAL(valueChanged(float, int)), this, SLOT(setFloatParameter(float, int)));
+ ++row;
+ }
+ }
+ }
+ file.close();
+ }
+ }
+
+ layout->addWidget(new QLabel(tr("Texture:")));
+ m_textureCombo = new QComboBox;
+ connect(m_textureCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(textureChanged(int)));
+ layout->addWidget(m_textureCombo);
+ ++row;
+
+ layout->addWidget(new QLabel(tr("Shader:")));
+ m_shaderCombo = new QComboBox;
+ connect(m_shaderCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(shaderChanged(int)));
+ layout->addWidget(m_shaderCombo);
+ ++row;
+
+ layout->setRowStretch(row, 1);
+}
+
+int RenderOptionsDialog::addTexture(const QString &name)
+{
+ m_textureCombo->addItem(name);
+ return m_textureCombo->count() - 1;
+}
+
+int RenderOptionsDialog::addShader(const QString &name)
+{
+ m_shaderCombo->addItem(name);
+ return m_shaderCombo->count() - 1;
+}
+
+void RenderOptionsDialog::emitParameterChanged()
+{
+ foreach (ParameterEdit *edit, m_parameterEdits)
+ edit->emitChange();
+}
+
+void RenderOptionsDialog::setColorParameter(QRgb color, int id)
+{
+ emit colorParameterChanged(m_parameterNames[id], color);
+}
+
+void RenderOptionsDialog::setFloatParameter(float value, int id)
+{
+ emit floatParameterChanged(m_parameterNames[id], value);
+}
+
+void RenderOptionsDialog::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton)
+ emit doubleClicked();
+}
+
+//============================================================================//
+// ItemDialog //
+//============================================================================//
+
+ItemDialog::ItemDialog()
+ : QDialog(0, Qt::CustomizeWindowHint | Qt::WindowTitleHint)
+{
+ setWindowTitle(tr("Items (double click to flip)"));
+ setWindowOpacity(0.75);
+ resize(160, 100);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ setLayout(layout);
+ QPushButton *button;
+
+ button = new QPushButton(tr("Add Qt box"));
+ layout->addWidget(button);
+ connect(button, SIGNAL(clicked()), this, SLOT(triggerNewQtBox()));
+
+ button = new QPushButton(tr("Add circle"));
+ layout->addWidget(button);
+ connect(button, SIGNAL(clicked()), this, SLOT(triggerNewCircleItem()));
+
+ button = new QPushButton(tr("Add square"));
+ layout->addWidget(button);
+ connect(button, SIGNAL(clicked()), this, SLOT(triggerNewSquareItem()));
+
+ layout->addStretch(1);
+}
+
+void ItemDialog::triggerNewQtBox()
+{
+ emit newItemTriggered(QtBoxItem);
+}
+
+void ItemDialog::triggerNewCircleItem()
+{
+ emit newItemTriggered(CircleItem);
+}
+
+void ItemDialog::triggerNewSquareItem()
+{
+ emit newItemTriggered(SquareItem);
+}
+
+void ItemDialog::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton)
+ emit doubleClicked();
+}
+
+//============================================================================//
+// Scene //
+//============================================================================//
+
+const static char environmentShaderText[] =
+ "uniform samplerCube env;"
+ "void main() {"
+ "gl_FragColor = textureCube(env, gl_TexCoord[1].xyz);"
+ "}";
+
+Scene::Scene(int width, int height, int maxTextureSize)
+ : m_distExp(600)
+ , m_frame(0)
+ , m_maxTextureSize(maxTextureSize)
+ , m_currentShader(0)
+ , m_currentTexture(0)
+ , m_dynamicCubemap(false)
+ , m_updateAllCubemaps(true)
+ , m_box(0)
+ , m_vertexShader(0)
+ , m_environmentShader(0)
+ , m_environmentProgram(0)
+{
+ setSceneRect(0, 0, width, height);
+
+ m_trackBalls[0] = TrackBall(0.0005f, gfx::Vector3f::vector(0, 1, 0), TrackBall::Sphere);
+ m_trackBalls[1] = TrackBall(0.0001f, gfx::Vector3f::vector(0, 0, 1), TrackBall::Sphere);
+ m_trackBalls[2] = TrackBall(0.0f, gfx::Vector3f::vector(0, 1, 0), TrackBall::Plane);
+
+ m_renderOptions = new RenderOptionsDialog;
+ m_renderOptions->move(20, 120);
+ m_renderOptions->resize(m_renderOptions->sizeHint());
+
+ connect(m_renderOptions, SIGNAL(dynamicCubemapToggled(int)), this, SLOT(toggleDynamicCubemap(int)));
+ connect(m_renderOptions, SIGNAL(colorParameterChanged(const QString &, QRgb)), this, SLOT(setColorParameter(const QString &, QRgb)));
+ connect(m_renderOptions, SIGNAL(floatParameterChanged(const QString &, float)), this, SLOT(setFloatParameter(const QString &, float)));
+ connect(m_renderOptions, SIGNAL(textureChanged(int)), this, SLOT(setTexture(int)));
+ connect(m_renderOptions, SIGNAL(shaderChanged(int)), this, SLOT(setShader(int)));
+
+ m_itemDialog = new ItemDialog;
+ connect(m_itemDialog, SIGNAL(newItemTriggered(ItemDialog::ItemType)), this, SLOT(newItem(ItemDialog::ItemType)));
+
+ TwoSidedGraphicsWidget *twoSided = new TwoSidedGraphicsWidget(this);
+ twoSided->setWidget(0, m_renderOptions);
+ twoSided->setWidget(1, m_itemDialog);
+
+ connect(m_renderOptions, SIGNAL(doubleClicked()), twoSided, SLOT(flip()));
+ connect(m_itemDialog, SIGNAL(doubleClicked()), twoSided, SLOT(flip()));
+
+ addItem(new QtBox(64, width - 64, height - 64));
+ addItem(new QtBox(64, width - 64, 64));
+ addItem(new QtBox(64, 64, height - 64));
+ addItem(new QtBox(64, 64, 64));
+
+ initGL();
+
+ m_timer = new QTimer(this);
+ m_timer->setInterval(20);
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(update()));
+ m_timer->start();
+
+ m_time.start();
+}
+
+Scene::~Scene()
+{
+ if (m_box)
+ delete m_box;
+ foreach (GLTexture *texture, m_textures)
+ if (texture) delete texture;
+ if (m_mainCubemap)
+ delete m_mainCubemap;
+ foreach (GLProgram *program, m_programs)
+ if (program) delete program;
+ if (m_vertexShader)
+ delete m_vertexShader;
+ foreach (GLFragmentShader *shader, m_fragmentShaders)
+ if (shader) delete shader;
+ foreach (GLRenderTargetCube *rt, m_cubemaps)
+ if (rt) delete rt;
+ if (m_environmentShader)
+ delete m_environmentShader;
+ if (m_environmentProgram)
+ delete m_environmentProgram;
+}
+
+void Scene::initGL()
+{
+ m_box = new GLRoundedBox(0.25f, 1.0f, 10);
+
+ m_vertexShader = new GLVertexShader(":/res/boxes/basic.vsh");
+
+ QStringList list;
+ list << ":/res/boxes/cubemap_posx.jpg" << ":/res/boxes/cubemap_negx.jpg" << ":/res/boxes/cubemap_posy.jpg"
+ << ":/res/boxes/cubemap_negy.jpg" << ":/res/boxes/cubemap_posz.jpg" << ":/res/boxes/cubemap_negz.jpg";
+ m_environment = new GLTextureCube(list, qMin(1024, m_maxTextureSize));
+ m_environmentShader = new GLFragmentShader(environmentShaderText, strlen(environmentShaderText));
+ m_environmentProgram = new GLProgram;
+ m_environmentProgram->attach(*m_vertexShader);
+ m_environmentProgram->attach(*m_environmentShader);
+
+ const int NOISE_SIZE = 128; // for a different size, B and BM in fbm.c must also be changed
+ m_noise = new GLTexture3D(NOISE_SIZE, NOISE_SIZE, NOISE_SIZE);
+ QRgb *data = new QRgb[NOISE_SIZE * NOISE_SIZE * NOISE_SIZE];
+ memset(data, 0, NOISE_SIZE * NOISE_SIZE * NOISE_SIZE * sizeof(QRgb));
+ QRgb *p = data;
+ float pos[3];
+ for (int k = 0; k < NOISE_SIZE; ++k) {
+ pos[2] = k * (0x20 / (float)NOISE_SIZE);
+ for (int j = 0; j < NOISE_SIZE; ++j) {
+ for (int i = 0; i < NOISE_SIZE; ++i) {
+ for (int byte = 0; byte < 4; ++byte) {
+ pos[0] = (i + (byte & 1) * 16) * (0x20 / (float)NOISE_SIZE);
+ pos[1] = (j + (byte & 2) * 8) * (0x20 / (float)NOISE_SIZE);
+ *p |= (int)(128.0f * (noise3(pos) + 1.0f)) << (byte * 8);
+ }
+ ++p;
+ }
+ }
+ }
+ m_noise->load(NOISE_SIZE, NOISE_SIZE, NOISE_SIZE, data);
+ delete[] data;
+
+ m_mainCubemap = new GLRenderTargetCube(512);
+
+ QStringList filter;
+ QList<QFileInfo> files;
+
+ // Load all .png files as textures
+ m_currentTexture = 0;
+ filter = QStringList("*.png");
+ files = QDir(":/res/boxes/").entryInfoList(filter, QDir::Files | QDir::Readable);
+
+ foreach (QFileInfo file, files) {
+ GLTexture *texture = new GLTexture2D(file.absoluteFilePath(), qMin(256, m_maxTextureSize), qMin(256, m_maxTextureSize));
+ if (texture->failed()) {
+ delete texture;
+ continue;
+ }
+ m_textures << texture;
+ m_renderOptions->addTexture(file.baseName());
+ }
+
+ if (m_textures.size() == 0)
+ m_textures << new GLTexture2D(qMin(64, m_maxTextureSize), qMin(64, m_maxTextureSize));
+
+ // Load all .fsh files as fragment shaders
+ m_currentShader = 0;
+ filter = QStringList("*.fsh");
+ files = QDir(":/res/boxes/").entryInfoList(filter, QDir::Files | QDir::Readable);
+ foreach (QFileInfo file, files) {
+ GLProgram *program = new GLProgram;
+ GLFragmentShader* shader = new GLFragmentShader(file.absoluteFilePath());
+ // The program does not take ownership over the shaders, so store them in a vector so they can be deleted afterwards.
+ program->attach(*m_vertexShader);
+ program->attach(*shader);
+ if (program->failed()) {
+ qWarning("Failed to compile and link shader program");
+ qWarning("Vertex shader log:");
+ qWarning() << m_vertexShader->log();
+ qWarning() << "Fragment shader log ( file =" << file.absoluteFilePath() << "):";
+ qWarning() << shader->log();
+ qWarning("Shader program log:");
+ qWarning() << program->log();
+
+ delete shader;
+ delete program;
+ continue;
+ }
+
+ m_fragmentShaders << shader;
+ m_programs << program;
+ m_renderOptions->addShader(file.baseName());
+
+ program->bind();
+ m_cubemaps << (program->hasParameter("env") ? new GLRenderTargetCube(qMin(256, m_maxTextureSize)) : 0);
+ program->unbind();
+ }
+
+ if (m_programs.size() == 0)
+ m_programs << new GLProgram;
+
+ m_renderOptions->emitParameterChanged();
+}
+
+// If one of the boxes should not be rendered, set excludeBox to its index.
+// If the main box should not be rendered, set excludeBox to -1.
+void Scene::renderBoxes(const gfx::Matrix4x4f &view, int excludeBox)
+{
+ gfx::Matrix4x4f invView = view.inverse();
+
+ // If multi-texturing is supported, use three saplers.
+ if (glActiveTexture) {
+ glActiveTexture(GL_TEXTURE0);
+ m_textures[m_currentTexture]->bind();
+ glActiveTexture(GL_TEXTURE2);
+ m_noise->bind();
+ glActiveTexture(GL_TEXTURE1);
+ } else {
+ m_textures[m_currentTexture]->bind();
+ }
+
+ glDisable(GL_LIGHTING);
+ glDisable(GL_CULL_FACE);
+
+ gfx::Matrix4x4f viewRotation(view);
+ viewRotation(3, 0) = viewRotation(3, 1) = viewRotation(3, 2) = 0.0f;
+ viewRotation(0, 3) = viewRotation(1, 3) = viewRotation(2, 3) = 0.0f;
+ viewRotation(3, 3) = 1.0f;
+ glLoadMatrixf(viewRotation.bits());
+ glScalef(20.0f, 20.0f, 20.0f);
+
+ // Don't render the environment if the environment texture can't be set for the correct sampler.
+ if (glActiveTexture) {
+ m_environment->bind();
+ m_environmentProgram->bind();
+ m_environmentProgram->setInt("tex", 0);
+ m_environmentProgram->setInt("env", 1);
+ m_environmentProgram->setInt("noise", 2);
+ m_box->draw();
+ m_environmentProgram->unbind();
+ m_environment->unbind();
+ }
+
+ glLoadMatrixf(view.bits());
+
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+
+ for (int i = 0; i < m_programs.size(); ++i) {
+ if (i == excludeBox)
+ continue;
+
+ glPushMatrix();
+ gfx::Matrix4x4f m;
+ m_trackBalls[1].rotation().matrix(m);
+ glMultMatrixf(m.bits());
+
+ glRotatef(360.0f * i / m_programs.size(), 0.0f, 0.0f, 1.0f);
+ glTranslatef(2.0f, 0.0f, 0.0f);
+ glScalef(0.3f, 0.6f, 0.6f);
+
+ if (glActiveTexture) {
+ if (m_dynamicCubemap && m_cubemaps[i])
+ m_cubemaps[i]->bind();
+ else
+ m_environment->bind();
+ }
+ m_programs[i]->bind();
+ m_programs[i]->setInt("tex", 0);
+ m_programs[i]->setInt("env", 1);
+ m_programs[i]->setInt("noise", 2);
+ m_programs[i]->setMatrix("view", view);
+ m_programs[i]->setMatrix("invView", invView);
+ m_box->draw();
+ m_programs[i]->unbind();
+
+ if (glActiveTexture) {
+ if (m_dynamicCubemap && m_cubemaps[i])
+ m_cubemaps[i]->unbind();
+ else
+ m_environment->unbind();
+ }
+ glPopMatrix();
+ }
+
+ if (-1 != excludeBox) {
+ gfx::Matrix4x4f m;
+ m_trackBalls[0].rotation().matrix(m);
+ glMultMatrixf(m.bits());
+
+ if (glActiveTexture) {
+ if (m_dynamicCubemap)
+ m_mainCubemap->bind();
+ else
+ m_environment->bind();
+ }
+
+ m_programs[m_currentShader]->bind();
+ m_programs[m_currentShader]->setInt("tex", 0);
+ m_programs[m_currentShader]->setInt("env", 1);
+ m_programs[m_currentShader]->setInt("noise", 2);
+ m_programs[m_currentShader]->setMatrix("view", view);
+ m_programs[m_currentShader]->setMatrix("invView", invView);
+ m_box->draw();
+ m_programs[m_currentShader]->unbind();
+
+ if (glActiveTexture) {
+ if (m_dynamicCubemap)
+ m_mainCubemap->unbind();
+ else
+ m_environment->unbind();
+ }
+ }
+
+ if (glActiveTexture) {
+ glActiveTexture(GL_TEXTURE2);
+ m_noise->unbind();
+ glActiveTexture(GL_TEXTURE0);
+ }
+ m_textures[m_currentTexture]->unbind();
+}
+
+void Scene::setStates()
+{
+ //glClearColor(0.25f, 0.25f, 0.5f, 1.0f);
+
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ //glEnable(GL_COLOR_MATERIAL);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_NORMALIZE);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ setLights();
+
+ float materialSpecular[] = {0.5f, 0.5f, 0.5f, 1.0f};
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, materialSpecular);
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 32.0f);
+}
+
+void Scene::setLights()
+{
+ glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
+ //float lightColour[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ float lightDir[] = {0.0f, 0.0f, 1.0f, 0.0f};
+ //glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColour);
+ //glLightfv(GL_LIGHT0, GL_SPECULAR, lightColour);
+ glLightfv(GL_LIGHT0, GL_POSITION, lightDir);
+ glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, 1.0f);
+ glEnable(GL_LIGHT0);
+}
+
+void Scene::defaultStates()
+{
+ //glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+ //glDisable(GL_COLOR_MATERIAL);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_LIGHT0);
+ glDisable(GL_NORMALIZE);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+
+ glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, 0.0f);
+ float defaultMaterialSpecular[] = {0.0f, 0.0f, 0.0f, 1.0f};
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, defaultMaterialSpecular);
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f);
+}
+
+void Scene::renderCubemaps()
+{
+ // To speed things up, only update the cubemaps for the small cubes every N frames.
+ const int N = (m_updateAllCubemaps ? 1 : 3);
+
+ gfx::Matrix4x4f mat;
+ GLRenderTargetCube::getProjectionMatrix(mat, 0.1f, 100.0f);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(mat.bits());
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+
+ gfx::Vector3f center;
+
+ for (int i = m_frame % N; i < m_cubemaps.size(); i += N) {
+ if (0 == m_cubemaps[i])
+ continue;
+
+ float angle = 2.0f * PI * i / m_cubemaps.size();
+ center = m_trackBalls[1].rotation().transform(gfx::Vector3f::vector(cos(angle), sin(angle), 0));
+
+ for (int face = 0; face < 6; ++face) {
+ m_cubemaps[i]->begin(face);
+
+ GLRenderTargetCube::getViewMatrix(mat, face);
+ gfx::Vector4f v = gfx::Vector4f::vector(-center[0], -center[1], -center[2], 1.0);
+ mat[3] = v * mat;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ renderBoxes(mat, i);
+
+ m_cubemaps[i]->end();
+ }
+ }
+
+ for (int face = 0; face < 6; ++face) {
+ m_mainCubemap->begin(face);
+ GLRenderTargetCube::getViewMatrix(mat, face);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ renderBoxes(mat, -1);
+
+ m_mainCubemap->end();
+ }
+
+ glPopMatrix();
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+
+ m_updateAllCubemaps = false;
+}
+
+void Scene::drawBackground(QPainter *painter, const QRectF &)
+{
+ float width = float(painter->device()->width());
+ float height = float(painter->device()->height());
+
+ setStates();
+
+ if (m_dynamicCubemap)
+ renderCubemaps();
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glMatrixMode(GL_PROJECTION);
+ gluPerspective(60.0, width / height, 0.01, 15.0);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ //gfx::Matrix4x4f view = gfx::Matrix4x4f::identity();
+ //view(3, 2) -= 2.0f * exp(m_distExp / 1200.0f);
+
+ gfx::Matrix4x4f view;
+ m_trackBalls[2].rotation().matrix(view);
+ view(3, 2) -= 2.0f * exp(m_distExp / 1200.0f);
+ renderBoxes(view);
+
+ defaultStates();
+ ++m_frame;
+}
+
+QPointF Scene::pixelPosToViewPos(const QPointF& p)
+{
+ return QPointF(2.0 * float(p.x()) / width() - 1.0,
+ 1.0 - 2.0 * float(p.y()) / height());
+}
+
+void Scene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ QGraphicsScene::mouseMoveEvent(event);
+ if (event->isAccepted())
+ return;
+
+ if (event->buttons() & Qt::LeftButton) {
+ m_trackBalls[0].move(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ event->accept();
+ } else {
+ m_trackBalls[0].release(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ }
+
+ if (event->buttons() & Qt::RightButton) {
+ m_trackBalls[1].move(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ event->accept();
+ } else {
+ m_trackBalls[1].release(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ }
+
+ if (event->buttons() & Qt::MidButton) {
+ m_trackBalls[2].move(pixelPosToViewPos(event->scenePos()), gfx::Quaternionf::identity());
+ event->accept();
+ } else {
+ m_trackBalls[2].release(pixelPosToViewPos(event->scenePos()), gfx::Quaternionf::identity());
+ }
+}
+
+void Scene::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ QGraphicsScene::mousePressEvent(event);
+ if (event->isAccepted())
+ return;
+
+ if (event->buttons() & Qt::LeftButton) {
+ m_trackBalls[0].push(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ event->accept();
+ }
+
+ if (event->buttons() & Qt::RightButton) {
+ m_trackBalls[1].push(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ event->accept();
+ }
+
+ if (event->buttons() & Qt::MidButton) {
+ m_trackBalls[2].push(pixelPosToViewPos(event->scenePos()), gfx::Quaternionf::identity());
+ event->accept();
+ }
+}
+
+void Scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ QGraphicsScene::mouseReleaseEvent(event);
+ if (event->isAccepted())
+ return;
+
+ if (event->button() == Qt::LeftButton) {
+ m_trackBalls[0].release(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ event->accept();
+ }
+
+ if (event->button() == Qt::RightButton) {
+ m_trackBalls[1].release(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ event->accept();
+ }
+
+ if (event->button() == Qt::MidButton) {
+ m_trackBalls[2].release(pixelPosToViewPos(event->scenePos()), gfx::Quaternionf::identity());
+ event->accept();
+ }
+}
+
+void Scene::wheelEvent(QGraphicsSceneWheelEvent * event)
+{
+ QGraphicsScene::wheelEvent(event);
+ if (!event->isAccepted()) {
+ m_distExp += event->delta();
+ if (m_distExp < -8 * 120)
+ m_distExp = -8 * 120;
+ if (m_distExp > 10 * 120)
+ m_distExp = 10 * 120;
+ event->accept();
+ }
+}
+
+void Scene::setShader(int index)
+{
+ if (index >= 0 && index < m_fragmentShaders.size())
+ m_currentShader = index;
+}
+
+void Scene::setTexture(int index)
+{
+ if (index >= 0 && index < m_textures.size())
+ m_currentTexture = index;
+}
+
+void Scene::toggleDynamicCubemap(int state)
+{
+ if ((m_dynamicCubemap = (state == Qt::Checked)))
+ m_updateAllCubemaps = true;
+}
+
+void Scene::setColorParameter(const QString &name, QRgb color)
+{
+ // set the color in all programs
+ foreach (GLProgram *program, m_programs) {
+ program->bind();
+ program->setColor(name, color);
+ program->unbind();
+ }
+}
+
+void Scene::setFloatParameter(const QString &name, float value)
+{
+ // set the color in all programs
+ foreach (GLProgram *program, m_programs) {
+ program->bind();
+ program->setFloat(name, value);
+ program->unbind();
+ }
+}
+
+void Scene::newItem(ItemDialog::ItemType type)
+{
+ QSize size = sceneRect().size().toSize();
+ switch (type) {
+ case ItemDialog::QtBoxItem:
+ addItem(new QtBox(64, rand() % (size.width() - 64) + 32, rand() % (size.height() - 64) + 32));
+ break;
+ case ItemDialog::CircleItem:
+ addItem(new CircleItem(64, rand() % (size.width() - 64) + 32, rand() % (size.height() - 64) + 32));
+ break;
+ case ItemDialog::SquareItem:
+ addItem(new SquareItem(64, rand() % (size.width() - 64) + 32, rand() % (size.height() - 64) + 32));
+ break;
+ default:
+ break;
+ }
+}
diff --git a/demos/boxes/scene.h b/demos/boxes/scene.h
new file mode 100644
index 0000000..2db9317
--- /dev/null
+++ b/demos/boxes/scene.h
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SCENE_H
+#define SCENE_H
+
+//#include <GL/glew.h>
+#include "glextensions.h"
+
+#include <QtGui>
+#include <QtOpenGL>
+
+#include "roundedbox.h"
+#include "gltrianglemesh.h"
+#include "vector.h"
+#include "trackball.h"
+#include "glbuffers.h"
+#include "glshaders.h"
+#include "qtbox.h"
+
+#define PI 3.14159265358979
+
+class ParameterEdit : public QWidget
+{
+public:
+ virtual void emitChange() = 0;
+};
+
+class ColorEdit : public ParameterEdit
+{
+ Q_OBJECT
+public:
+ ColorEdit(QRgb initialColor, int id);
+ QRgb color() const {return m_color;}
+ virtual void emitChange() {emit colorChanged(m_color, m_id);}
+public slots:
+ void editDone();
+signals:
+ void colorChanged(QRgb color, int id);
+protected:
+ virtual void mousePressEvent(QMouseEvent *event);
+ void setColor(QRgb color); // also emits colorChanged()
+private:
+ QGraphicsScene *m_dialogParentScene;
+ QLineEdit *m_lineEdit;
+ QFrame *m_button;
+ QRgb m_color;
+ int m_id;
+};
+
+class FloatEdit : public ParameterEdit
+{
+ Q_OBJECT
+public:
+ FloatEdit(float initialValue, int id);
+ float value() const {return m_value;}
+ virtual void emitChange() {emit valueChanged(m_value, m_id);}
+public slots:
+ void editDone();
+signals:
+ void valueChanged(float value, int id);
+private:
+ QGraphicsScene *m_dialogParentScene;
+ QLineEdit *m_lineEdit;
+ float m_value;
+ int m_id;
+};
+
+class GraphicsWidget : public QGraphicsProxyWidget
+{
+protected:
+ virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+ virtual void resizeEvent(QGraphicsSceneResizeEvent *event);
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+};
+
+class TwoSidedGraphicsWidget : public QObject
+{
+ Q_OBJECT
+public:
+ TwoSidedGraphicsWidget(QGraphicsScene *scene);
+ void setWidget(int index, QWidget *widget);
+ QWidget *widget(int index);
+public slots:
+ void flip();
+protected slots:
+ void animateFlip();
+private:
+ GraphicsWidget *m_proxyWidgets[2];
+ int m_current;
+ int m_angle; // angle in degrees
+ int m_delta;
+};
+
+class RenderOptionsDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ RenderOptionsDialog();
+ int addTexture(const QString &name);
+ int addShader(const QString &name);
+ void emitParameterChanged();
+protected slots:
+ void setColorParameter(QRgb color, int id);
+ void setFloatParameter(float value, int id);
+signals:
+ void dynamicCubemapToggled(int);
+ void colorParameterChanged(const QString &, QRgb);
+ void floatParameterChanged(const QString &, float);
+ void textureChanged(int);
+ void shaderChanged(int);
+ void doubleClicked();
+protected:
+ virtual void mouseDoubleClickEvent(QMouseEvent *event);
+
+ QVector<QByteArray> m_parameterNames;
+ QComboBox *m_textureCombo;
+ QComboBox *m_shaderCombo;
+ QVector<ParameterEdit *> m_parameterEdits;
+};
+
+class ItemDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ enum ItemType {
+ QtBoxItem,
+ CircleItem,
+ SquareItem,
+ };
+
+ ItemDialog();
+public slots:
+ void triggerNewQtBox();
+ void triggerNewCircleItem();
+ void triggerNewSquareItem();
+signals:
+ void doubleClicked();
+ void newItemTriggered(ItemDialog::ItemType type);
+protected:
+ virtual void mouseDoubleClickEvent(QMouseEvent *event);
+};
+
+class Scene : public QGraphicsScene
+{
+ Q_OBJECT
+public:
+ Scene(int width, int height, int maxTextureSize);
+ ~Scene();
+ virtual void drawBackground(QPainter *painter, const QRectF &rect);
+
+public slots:
+ void setShader(int index);
+ void setTexture(int index);
+ void toggleDynamicCubemap(int state);
+ void setColorParameter(const QString &name, QRgb color);
+ void setFloatParameter(const QString &name, float value);
+ void newItem(ItemDialog::ItemType type);
+protected:
+ void renderBoxes(const gfx::Matrix4x4f &view, int excludeBox = -2);
+ void setStates();
+ void setLights();
+ void defaultStates();
+ void renderCubemaps();
+
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void wheelEvent(QGraphicsSceneWheelEvent * event);
+private:
+ void initGL();
+ QPointF pixelPosToViewPos(const QPointF& p);
+
+ QTime m_time;
+ int m_lastTime;
+ int m_mouseEventTime;
+ int m_distExp;
+ int m_frame;
+ int m_maxTextureSize;
+
+ int m_currentShader;
+ int m_currentTexture;
+ bool m_dynamicCubemap;
+ bool m_updateAllCubemaps;
+
+ RenderOptionsDialog *m_renderOptions;
+ ItemDialog *m_itemDialog;
+ QTimer *m_timer;
+ GLRoundedBox *m_box;
+ TrackBall m_trackBalls[3];
+ QVector<GLTexture *> m_textures;
+ GLTextureCube *m_environment;
+ GLTexture3D *m_noise;
+ GLRenderTargetCube *m_mainCubemap;
+ QVector<GLRenderTargetCube *> m_cubemaps;
+ QVector<GLProgram *> m_programs;
+ GLVertexShader *m_vertexShader;
+ QVector<GLFragmentShader *> m_fragmentShaders;
+ GLFragmentShader *m_environmentShader;
+ GLProgram *m_environmentProgram;
+};
+
+
+
+#endif
diff --git a/demos/boxes/smiley.png b/demos/boxes/smiley.png
new file mode 100644
index 0000000..41cfda6
--- /dev/null
+++ b/demos/boxes/smiley.png
Binary files differ
diff --git a/demos/boxes/square.jpg b/demos/boxes/square.jpg
new file mode 100644
index 0000000..03f53bd
--- /dev/null
+++ b/demos/boxes/square.jpg
Binary files differ
diff --git a/demos/boxes/trackball.cpp b/demos/boxes/trackball.cpp
new file mode 100644
index 0000000..980f6ed
--- /dev/null
+++ b/demos/boxes/trackball.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "trackball.h"
+
+//============================================================================//
+// TrackBall //
+//============================================================================//
+
+TrackBall::TrackBall(TrackMode mode)
+ : m_angularVelocity(0)
+ , m_paused(false)
+ , m_pressed(false)
+ , m_mode(mode)
+{
+ m_axis = gfx::Vector3f::vector(0, 1, 0);
+ m_rotation = gfx::Quaternionf::quaternion(1.0f, 0.0f, 0.0f, 0.0f);
+ m_lastTime = QTime::currentTime();
+}
+
+TrackBall::TrackBall(float angularVelocity, const gfx::Vector3f& axis, TrackMode mode)
+ : m_axis(axis)
+ , m_angularVelocity(angularVelocity)
+ , m_paused(false)
+ , m_pressed(false)
+ , m_mode(mode)
+{
+ m_rotation = gfx::Quaternionf::quaternion(1.0f, 0.0f, 0.0f, 0.0f);
+ m_lastTime = QTime::currentTime();
+}
+
+void TrackBall::push(const QPointF& p, const gfx::Quaternionf &)
+{
+ m_rotation = rotation();
+ m_pressed = true;
+ m_lastTime = QTime::currentTime();
+ m_lastPos = p;
+ m_angularVelocity = 0.0f;
+}
+
+void TrackBall::move(const QPointF& p, const gfx::Quaternionf &transformation)
+{
+ if (!m_pressed)
+ return;
+
+ QTime currentTime = QTime::currentTime();
+ int msecs = m_lastTime.msecsTo(currentTime);
+ if (msecs <= 20)
+ return;
+
+ switch (m_mode) {
+ case Plane:
+ {
+ QLineF delta(m_lastPos, p);
+ m_angularVelocity = delta.length() / msecs;
+ m_axis = gfx::Vector3f::vector(delta.dy(), -delta.dx(), 0.0f).normalized();
+ m_axis = transformation.transform(m_axis);
+ m_rotation *= gfx::Quaternionf::rotation(delta.length(), m_axis);
+ }
+ break;
+ case Sphere:
+ {
+ gfx::Vector3f lastPos3D = gfx::Vector3f::vector(m_lastPos.x(), m_lastPos.y(), 0);
+ float sqrZ = 1 - lastPos3D.sqrNorm();
+ if (sqrZ > 0)
+ lastPos3D[2] = sqrt(sqrZ);
+ else
+ lastPos3D.normalize();
+
+ gfx::Vector3f currentPos3D = gfx::Vector3f::vector(p.x(), p.y(), 0);
+ sqrZ = 1 - currentPos3D.sqrNorm();
+ if (sqrZ > 0)
+ currentPos3D[2] = sqrt(sqrZ);
+ else
+ currentPos3D.normalize();
+
+ m_axis = gfx::Vector3f::cross(currentPos3D, lastPos3D);
+ float angle = asin(sqrt(m_axis.sqrNorm()));
+
+ m_angularVelocity = angle / msecs;
+ m_axis.normalize();
+ m_axis = transformation.transform(m_axis);
+ m_rotation *= gfx::Quaternionf::rotation(angle, m_axis);
+ }
+ break;
+ }
+
+ m_lastPos = p;
+ m_lastTime = currentTime;
+}
+
+void TrackBall::release(const QPointF& p, const gfx::Quaternionf &transformation)
+{
+ // Calling move() caused the rotation to stop if the framerate was too low.
+ move(p, transformation);
+ m_pressed = false;
+}
+
+void TrackBall::start()
+{
+ m_lastTime = QTime::currentTime();
+ m_paused = false;
+}
+
+void TrackBall::stop()
+{
+ m_rotation = rotation();
+ m_paused = true;
+}
+
+gfx::Quaternionf TrackBall::rotation() const
+{
+ if (m_paused || m_pressed)
+ return m_rotation;
+
+ QTime currentTime = QTime::currentTime();
+ float angle = m_angularVelocity * m_lastTime.msecsTo(currentTime);
+ return m_rotation * gfx::Quaternionf::rotation(angle, m_axis);
+}
+
diff --git a/demos/boxes/trackball.h b/demos/boxes/trackball.h
new file mode 100644
index 0000000..5e3f40c
--- /dev/null
+++ b/demos/boxes/trackball.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TRACKBALL_H
+#define TRACKBALL_H
+
+#include <QtGui>
+
+#include "vector.h"
+
+class TrackBall
+{
+public:
+ enum TrackMode
+ {
+ Plane,
+ Sphere,
+ };
+ TrackBall(TrackMode mode = Sphere);
+ TrackBall(float angularVelocity, const gfx::Vector3f& axis, TrackMode mode = Sphere);
+ // coordinates in [-1,1]x[-1,1]
+ void push(const QPointF& p, const gfx::Quaternionf &transformation);
+ void move(const QPointF& p, const gfx::Quaternionf &transformation);
+ void release(const QPointF& p, const gfx::Quaternionf &transformation);
+ void start(); // starts clock
+ void stop(); // stops clock
+ gfx::Quaternionf rotation() const;
+private:
+ gfx::Quaternionf m_rotation;
+ gfx::Vector3f m_axis;
+ float m_angularVelocity;
+
+ QPointF m_lastPos;
+ QTime m_lastTime;
+ bool m_paused;
+ bool m_pressed;
+ TrackMode m_mode;
+};
+
+#endif
diff --git a/demos/boxes/vector.h b/demos/boxes/vector.h
new file mode 100644
index 0000000..bb24531
--- /dev/null
+++ b/demos/boxes/vector.h
@@ -0,0 +1,602 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VECTOR_H
+#define VECTOR_H
+
+#include <cassert>
+#include <cmath>
+#include <iostream>
+
+namespace gfx
+{
+
+template<class T, int n>
+struct Vector
+{
+ // Keep the Vector struct a plain old data (POD) struct by avoiding constructors
+
+ static Vector vector(T x)
+ {
+ Vector result;
+ for (int i = 0; i < n; ++i)
+ result.v[i] = x;
+ return result;
+ }
+
+ // Use only for 2D vectors
+ static Vector vector(T x, T y)
+ {
+ assert(n == 2);
+ Vector result;
+ result.v[0] = x;
+ result.v[1] = y;
+ return result;
+ }
+
+ // Use only for 3D vectors
+ static Vector vector(T x, T y, T z)
+ {
+ assert(n == 3);
+ Vector result;
+ result.v[0] = x;
+ result.v[1] = y;
+ result.v[2] = z;
+ return result;
+ }
+
+ // Use only for 4D vectors
+ static Vector vector(T x, T y, T z, T w)
+ {
+ assert(n == 4);
+ Vector result;
+ result.v[0] = x;
+ result.v[1] = y;
+ result.v[2] = z;
+ result.v[3] = w;
+ return result;
+ }
+
+ // Pass 'n' arguments to this function.
+ static Vector vector(T *v)
+ {
+ Vector result;
+ for (int i = 0; i < n; ++i)
+ result.v[i] = v[i];
+ return result;
+ }
+
+ T &operator [] (int i) {return v[i];}
+ T operator [] (int i) const {return v[i];}
+
+#define VECTOR_BINARY_OP(op, arg, rhs) \
+ Vector operator op (arg) const \
+ { \
+ Vector result; \
+ for (int i = 0; i < n; ++i) \
+ result.v[i] = v[i] op rhs; \
+ return result; \
+ }
+
+ VECTOR_BINARY_OP(+, const Vector &u, u.v[i])
+ VECTOR_BINARY_OP(-, const Vector &u, u.v[i])
+ VECTOR_BINARY_OP(*, const Vector &u, u.v[i])
+ VECTOR_BINARY_OP(/, const Vector &u, u.v[i])
+ VECTOR_BINARY_OP(+, T s, s)
+ VECTOR_BINARY_OP(-, T s, s)
+ VECTOR_BINARY_OP(*, T s, s)
+ VECTOR_BINARY_OP(/, T s, s)
+#undef VECTOR_BINARY_OP
+
+ Vector operator - () const
+ {
+ Vector result;
+ for (int i = 0; i < n; ++i)
+ result.v[i] = -v[i];
+ return result;
+ }
+
+#define VECTOR_ASSIGN_OP(op, arg, rhs) \
+ Vector &operator op (arg) \
+ { \
+ for (int i = 0; i < n; ++i) \
+ v[i] op rhs; \
+ return *this; \
+ }
+
+ VECTOR_ASSIGN_OP(+=, const Vector &u, u.v[i])
+ VECTOR_ASSIGN_OP(-=, const Vector &u, u.v[i])
+ VECTOR_ASSIGN_OP(=, T s, s)
+ VECTOR_ASSIGN_OP(*=, T s, s)
+ VECTOR_ASSIGN_OP(/=, T s, s)
+#undef VECTOR_ASSIGN_OP
+
+ static T dot(const Vector &u, const Vector &v)
+ {
+ T sum(0);
+ for (int i = 0; i < n; ++i)
+ sum += u.v[i] * v.v[i];
+ return sum;
+ }
+
+ static Vector cross(const Vector &u, const Vector &v)
+ {
+ assert(n == 3);
+ return vector(u.v[1] * v.v[2] - u.v[2] * v.v[1],
+ u.v[2] * v.v[0] - u.v[0] * v.v[2],
+ u.v[0] * v.v[1] - u.v[1] * v.v[0]);
+ }
+
+ T sqrNorm() const
+ {
+ return dot(*this, *this);
+ }
+
+ // requires floating point type T
+ void normalize()
+ {
+ T s = sqrNorm();
+ if (s != 0)
+ *this /= sqrt(s);
+ }
+
+ // requires floating point type T
+ Vector normalized() const
+ {
+ T s = sqrNorm();
+ if (s == 0)
+ return *this;
+ return *this / sqrt(s);
+ }
+
+ T *bits() {return v;}
+ const T *bits() const {return v;}
+
+ T v[n];
+};
+
+#define SCALAR_VECTOR_BINARY_OP(op) \
+template<class T, int n> \
+Vector<T, n> operator op (T s, const Vector<T, n>& u) \
+{ \
+ Vector<T, n> result; \
+ for (int i = 0; i < n; ++i) \
+ result[i] = s op u[i]; \
+ return result; \
+}
+
+SCALAR_VECTOR_BINARY_OP(+)
+SCALAR_VECTOR_BINARY_OP(-)
+SCALAR_VECTOR_BINARY_OP(*)
+SCALAR_VECTOR_BINARY_OP(/)
+#undef SCALAR_VECTOR_BINARY_OP
+
+template<class T, int n>
+std::ostream &operator << (std::ostream &os, const Vector<T, n> &v)
+{
+ assert(n > 0);
+ os << "[" << v[0];
+ for (int i = 1; i < n; ++i)
+ os << ", " << v[i];
+ os << "]";
+ return os;
+}
+
+typedef Vector<float, 2> Vector2f;
+typedef Vector<float, 3> Vector3f;
+typedef Vector<float, 4> Vector4f;
+
+template<class T, int rows, int cols>
+struct Matrix
+{
+ // Keep the Matrix struct a plain old data (POD) struct by avoiding constructors
+
+ static Matrix matrix(T x)
+ {
+ Matrix result;
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < cols; ++j)
+ result.v[i][j] = x;
+ }
+ return result;
+ }
+
+ static Matrix matrix(T *m)
+ {
+ Matrix result;
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < cols; ++j) {
+ result.v[i][j] = *m;
+ ++m;
+ }
+ }
+ return result;
+ }
+
+ T &operator () (int i, int j) {return v[i][j];}
+ T operator () (int i, int j) const {return v[i][j];}
+ Vector<T, cols> &operator [] (int i) {return v[i];}
+ const Vector<T, cols> &operator [] (int i) const {return v[i];}
+
+ // TODO: operators, methods
+
+ Vector<T, rows> operator * (const Vector<T, cols> &u) const
+ {
+ Vector<T, rows> result;
+ for (int i = 0; i < rows; ++i)
+ result[i] = Vector<T, cols>::dot(v[i], u);
+ return result;
+ }
+
+ template<int k>
+ Matrix<T, rows, k> operator * (const Matrix<T, cols, k> &m)
+ {
+ Matrix<T, rows, k> result;
+ for (int i = 0; i < rows; ++i)
+ result[i] = v[i] * m;
+ return result;
+ }
+
+ T* bits() {return reinterpret_cast<T *>(this);}
+ const T* bits() const {return reinterpret_cast<const T *>(this);}
+
+ // Simple Gauss elimination.
+ // TODO: Optimize and improve stability.
+ Matrix inverse(bool *ok = 0) const
+ {
+ assert(rows == cols);
+ Matrix rhs = identity();
+ Matrix lhs(*this);
+ T temp;
+ // Down
+ for (int i = 0; i < rows; ++i) {
+ // Pivoting
+ int pivot = i;
+ for (int j = i; j < rows; ++j) {
+ if (qAbs(lhs(j, i)) > lhs(pivot, i))
+ pivot = j;
+ }
+ // TODO: fuzzy compare.
+ if (lhs(pivot, i) == T(0)) {
+ if (ok)
+ *ok = false;
+ return rhs;
+ }
+ if (pivot != i) {
+ for (int j = i; j < cols; ++j) {
+ temp = lhs(pivot, j);
+ lhs(pivot, j) = lhs(i, j);
+ lhs(i, j) = temp;
+ }
+ for (int j = 0; j < cols; ++j) {
+ temp = rhs(pivot, j);
+ rhs(pivot, j) = rhs(i, j);
+ rhs(i, j) = temp;
+ }
+ }
+
+ // Normalize i-th row
+ rhs[i] /= lhs(i, i);
+ for (int j = cols - 1; j > i; --j)
+ lhs(i, j) /= lhs(i, i);
+
+ // Eliminate non-zeros in i-th column below the i-th row.
+ for (int j = i + 1; j < rows; ++j) {
+ rhs[j] -= lhs(j, i) * rhs[i];
+ for (int k = i + 1; k < cols; ++k)
+ lhs(j, k) -= lhs(j, i) * lhs(i, k);
+ }
+ }
+ // Up
+ for (int i = rows - 1; i > 0; --i) {
+ for (int j = i - 1; j >= 0; --j)
+ rhs[j] -= lhs(j, i) * rhs[i];
+ }
+ if (ok)
+ *ok = true;
+ return rhs;
+ }
+
+ Matrix<T, cols, rows> transpose() const
+ {
+ Matrix<T, cols, rows> result;
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < cols; ++j)
+ result.v[j][i] = v[i][j];
+ }
+ return result;
+ }
+
+ static Matrix identity()
+ {
+ Matrix result = matrix(T(0));
+ for (int i = 0; i < rows && i < cols; ++i)
+ result.v[i][i] = T(1);
+ return result;
+ }
+
+ Vector<T, cols> v[rows];
+};
+
+template<class T, int rows, int cols>
+Vector<T, cols> operator * (const Vector<T, rows> &u, const Matrix<T, rows, cols> &m)
+{
+ Vector<T, cols> result = Vector<T, cols>::vector(T(0));
+ for (int i = 0; i < rows; ++i)
+ result += m[i] * u[i];
+ return result;
+}
+
+template<class T, int rows, int cols>
+std::ostream &operator << (std::ostream &os, const Matrix<T, rows, cols> &m)
+{
+ assert(rows > 0);
+ os << "[" << m[0];
+ for (int i = 1; i < rows; ++i)
+ os << ", " << m[i];
+ os << "]";
+ return os;
+}
+
+
+typedef Matrix<float, 2, 2> Matrix2x2f;
+typedef Matrix<float, 3, 3> Matrix3x3f;
+typedef Matrix<float, 4, 4> Matrix4x4f;
+
+template<class T>
+struct Quaternion
+{
+ // Keep the Quaternion struct a plain old data (POD) struct by avoiding constructors
+
+ static Quaternion quaternion(T s, T x, T y, T z)
+ {
+ Quaternion result;
+ result.scalar = s;
+ result.vector[0] = x;
+ result.vector[1] = y;
+ result.vector[2] = z;
+ return result;
+ }
+
+ static Quaternion quaternion(T s, const Vector<T, 3> &v)
+ {
+ Quaternion result;
+ result.scalar = s;
+ result.vector = v;
+ return result;
+ }
+
+ static Quaternion identity()
+ {
+ return quaternion(T(1), T(0), T(0), T(0));
+ }
+
+ // assumes that all the elements are packed tightly
+ T& operator [] (int i) {return reinterpret_cast<T *>(this)[i];}
+ T operator [] (int i) const {return reinterpret_cast<const T *>(this)[i];}
+
+#define QUATERNION_BINARY_OP(op, arg, rhs) \
+ Quaternion operator op (arg) const \
+ { \
+ Quaternion result; \
+ for (int i = 0; i < 4; ++i) \
+ result[i] = (*this)[i] op rhs; \
+ return result; \
+ }
+
+ QUATERNION_BINARY_OP(+, const Quaternion &q, q[i])
+ QUATERNION_BINARY_OP(-, const Quaternion &q, q[i])
+ QUATERNION_BINARY_OP(*, T s, s)
+ QUATERNION_BINARY_OP(/, T s, s)
+#undef QUATERNION_BINARY_OP
+
+ Quaternion operator - () const
+ {
+ return Quaternion(-scalar, -vector);
+ }
+
+ Quaternion operator * (const Quaternion &q) const
+ {
+ Quaternion result;
+ result.scalar = scalar * q.scalar - Vector<T, 3>::dot(vector, q.vector);
+ result.vector = scalar * q.vector + vector * q.scalar + Vector<T, 3>::cross(vector, q.vector);
+ return result;
+ }
+
+ Quaternion operator * (const Vector<T, 3> &v) const
+ {
+ Quaternion result;
+ result.scalar = -Vector<T, 3>::dot(vector, v);
+ result.vector = scalar * v + Vector<T, 3>::cross(vector, v);
+ return result;
+ }
+
+ friend Quaternion operator * (const Vector<T, 3> &v, const Quaternion &q)
+ {
+ Quaternion result;
+ result.scalar = -Vector<T, 3>::dot(v, q.vector);
+ result.vector = v * q.scalar + Vector<T, 3>::cross(v, q.vector);
+ return result;
+ }
+
+#define QUATERNION_ASSIGN_OP(op, arg, rhs) \
+ Quaternion &operator op (arg) \
+ { \
+ for (int i = 0; i < 4; ++i) \
+ (*this)[i] op rhs; \
+ return *this; \
+ }
+
+ QUATERNION_ASSIGN_OP(+=, const Quaternion &q, q[i])
+ QUATERNION_ASSIGN_OP(-=, const Quaternion &q, q[i])
+ QUATERNION_ASSIGN_OP(=, T s, s)
+ QUATERNION_ASSIGN_OP(*=, T s, s)
+ QUATERNION_ASSIGN_OP(/=, T s, s)
+#undef QUATERNION_ASSIGN_OP
+
+ Quaternion& operator *= (const Quaternion &q)
+ {
+ Quaternion result;
+ result.scalar = scalar * q.scalar - Vector<T, 3>::dot(vector, q.vector);
+ result.vector = scalar * q.vector + vector * q.scalar + Vector<T, 3>::cross(vector, q.vector);
+ return (*this = result);
+ }
+
+ Quaternion& operator *= (const Vector<T, 3> &v)
+ {
+ Quaternion result;
+ result.scalar = -Vector<T, 3>::dot(vector, v);
+ result.vector = scalar * v + Vector<T, 3>::cross(vector, v);
+ return (*this = result);
+ }
+
+ Quaternion conjugate() const
+ {
+ return quaternion(scalar, -vector);
+ }
+
+ T sqrNorm() const
+ {
+ return scalar * scalar + vector.sqrNorm();
+ }
+
+ Quaternion inverse() const
+ {
+ return conjugate() / sqrNorm();
+ }
+
+ // requires floating point type T
+ Quaternion normalized() const
+ {
+ T s = sqrNorm();
+ if (s == 0)
+ return *this;
+ return *this / sqrt(s);
+ }
+
+ void matrix(Matrix<T, 3, 3>& m) const
+ {
+ T bb = vector[0] * vector[0];
+ T cc = vector[1] * vector[1];
+ T dd = vector[2] * vector[2];
+ T diag = scalar * scalar - bb - cc - dd;
+ T ab = scalar * vector[0];
+ T ac = scalar * vector[1];
+ T ad = scalar * vector[2];
+ T bc = vector[0] * vector[1];
+ T cd = vector[1] * vector[2];
+ T bd = vector[2] * vector[0];
+ m(0, 0) = diag + 2 * bb;
+ m(0, 1) = 2 * (bc - ad);
+ m(0, 2) = 2 * (ac + bd);
+ m(1, 0) = 2 * (ad + bc);
+ m(1, 1) = diag + 2 * cc;
+ m(1, 2) = 2 * (cd - ab);
+ m(2, 0) = 2 * (bd - ac);
+ m(2, 1) = 2 * (ab + cd);
+ m(2, 2) = diag + 2 * dd;
+ }
+
+ void matrix(Matrix<T, 4, 4>& m) const
+ {
+ T bb = vector[0] * vector[0];
+ T cc = vector[1] * vector[1];
+ T dd = vector[2] * vector[2];
+ T diag = scalar * scalar - bb - cc - dd;
+ T ab = scalar * vector[0];
+ T ac = scalar * vector[1];
+ T ad = scalar * vector[2];
+ T bc = vector[0] * vector[1];
+ T cd = vector[1] * vector[2];
+ T bd = vector[2] * vector[0];
+ m(0, 0) = diag + 2 * bb;
+ m(0, 1) = 2 * (bc - ad);
+ m(0, 2) = 2 * (ac + bd);
+ m(0, 3) = 0;
+ m(1, 0) = 2 * (ad + bc);
+ m(1, 1) = diag + 2 * cc;
+ m(1, 2) = 2 * (cd - ab);
+ m(1, 3) = 0;
+ m(2, 0) = 2 * (bd - ac);
+ m(2, 1) = 2 * (ab + cd);
+ m(2, 2) = diag + 2 * dd;
+ m(2, 3) = 0;
+ m(3, 0) = 0;
+ m(3, 1) = 0;
+ m(3, 2) = 0;
+ m(3, 3) = 1;
+ }
+
+ // assumes that 'this' is normalized
+ Vector<T, 3> transform(const Vector<T, 3> &v) const
+ {
+ Matrix<T, 3, 3> m;
+ matrix(m);
+ return v * m;
+ }
+
+ // assumes that all the elements are packed tightly
+ T* bits() {return reinterpret_cast<T *>(this);}
+ const T* bits() const {return reinterpret_cast<const T *>(this);}
+
+ // requires floating point type T
+ static Quaternion rotation(T angle, const Vector<T, 3> &unitAxis)
+ {
+ T s = sin(angle / 2);
+ T c = cos(angle / 2);
+ return quaternion(c, unitAxis * s);
+ }
+
+ T scalar;
+ Vector<T, 3> vector;
+};
+
+template<class T>
+Quaternion<T> operator * (T s, const Quaternion<T>& q)
+{
+ return Quaternion<T>::quaternion(s * q.scalar, s * q.vector);
+}
+
+typedef Quaternion<float> Quaternionf;
+
+} // end namespace gfx
+
+#endif
diff --git a/demos/boxes/wood.fsh b/demos/boxes/wood.fsh
new file mode 100644
index 0000000..35bf7d6
--- /dev/null
+++ b/demos/boxes/wood.fsh
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform sampler3D noise;
+
+//const vec4 woodColors[2] = {vec4(0.37,0.24,0.20,1), vec4(0.8,0.6,0.4,1)};
+uniform vec4 woodColors[2];
+//const float woodTubulence = 0.1;
+uniform float woodTubulence;
+
+void main()
+{
+ float r = length(gl_TexCoord[1].yz);
+ r += woodTubulence * texture3D(noise, 0.25 * gl_TexCoord[1].xyz).x;
+
+ vec3 N = normalize(normal);
+ // assume directional light
+
+ gl_MaterialParameters M = gl_FrontMaterial;
+
+ float NdotL = dot(N, lightDirection.xyz);
+ float RdotL = dot(reflect(normalize(position), N), lightDirection.xyz);
+
+ float f = fract(16.0 * r);
+ vec4 unlitColor = mix(woodColors[0], woodColors[1], min(1.25 * f, 5.0 - 5.0 * f));
+ gl_FragColor = (ambient + diffuse * max(NdotL, 0.0)) * unlitColor +
+ M.specular * specular * pow(max(RdotL, 0.0), M.shininess);
+}
diff --git a/demos/browser/Info_mac.plist b/demos/browser/Info_mac.plist
new file mode 100644
index 0000000..5648631
--- /dev/null
+++ b/demos/browser/Info_mac.plist
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleIconFile</key>
+ <string>@ICON@</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleGetInfoString</key>
+ <string>Created by Qt/QMake</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.trolltech.DemoBrowser</string>
+ <key>CFBundleSignature</key>
+ <string>ttxt</string>
+ <key>CFBundleExecutable</key>
+ <string>@EXECUTABLE@</string>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>html</string>
+ <string>htm</string>
+ <string>shtml</string>
+ <string>xht</string>
+ <string>xhtml</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>@ICON@</string>
+ <key>CFBundleTypeName</key>
+ <string>HTML Document</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>HTML</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ </dict>
+ </array>
+ <key>NOTE</key>
+ <string>DemoBrowser by Nokia Corporation and/or its subsidiary(-ies)</string>
+</dict>
+</plist>
diff --git a/demos/browser/addbookmarkdialog.ui b/demos/browser/addbookmarkdialog.ui
new file mode 100644
index 0000000..3460d7b
--- /dev/null
+++ b/demos/browser/addbookmarkdialog.ui
@@ -0,0 +1,98 @@
+<ui version="4.0" >
+ <class>AddBookmarkDialog</class>
+ <widget class="QDialog" name="AddBookmarkDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>240</width>
+ <height>168</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Add Bookmark</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Type a name for the bookmark, and choose where to keep it.</string>
+ </property>
+ <property name="textFormat" >
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="name" />
+ </item>
+ <item>
+ <widget class="QComboBox" name="location" />
+ </item>
+ <item>
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>2</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ <property name="centerButtons" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>AddBookmarkDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>AddBookmarkDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/demos/browser/autosaver.cpp b/demos/browser/autosaver.cpp
new file mode 100644
index 0000000..4e945f0
--- /dev/null
+++ b/demos/browser/autosaver.cpp
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "autosaver.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QMetaObject>
+#include <QtDebug>
+
+#define AUTOSAVE_IN 1000 * 3 // seconds
+#define MAXWAIT 1000 * 15 // seconds
+
+AutoSaver::AutoSaver(QObject *parent) : QObject(parent)
+{
+ Q_ASSERT(parent);
+}
+
+AutoSaver::~AutoSaver()
+{
+ if (m_timer.isActive())
+ qWarning() << "AutoSaver: still active when destroyed, changes not saved.";
+}
+
+void AutoSaver::changeOccurred()
+{
+ if (m_firstChange.isNull())
+ m_firstChange.start();
+
+ if (m_firstChange.elapsed() > MAXWAIT) {
+ saveIfNeccessary();
+ } else {
+ m_timer.start(AUTOSAVE_IN, this);
+ }
+}
+
+void AutoSaver::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == m_timer.timerId()) {
+ saveIfNeccessary();
+ } else {
+ QObject::timerEvent(event);
+ }
+}
+
+void AutoSaver::saveIfNeccessary()
+{
+ if (!m_timer.isActive())
+ return;
+ m_timer.stop();
+ m_firstChange = QTime();
+ if (!QMetaObject::invokeMethod(parent(), "save", Qt::DirectConnection)) {
+ qWarning() << "AutoSaver: error invoking slot save() on parent";
+ }
+}
+
diff --git a/demos/browser/autosaver.h b/demos/browser/autosaver.h
new file mode 100644
index 0000000..bb340cd
--- /dev/null
+++ b/demos/browser/autosaver.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef AUTOSAVER_H
+#define AUTOSAVER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QBasicTimer>
+#include <QtCore/QTime>
+
+/*
+ This class will call the save() slot on the parent object when the parent changes.
+ It will wait several seconds after changed() to combining multiple changes and
+ prevent continuous writing to disk.
+ */
+class AutoSaver : public QObject {
+
+Q_OBJECT
+
+public:
+ AutoSaver(QObject *parent);
+ ~AutoSaver();
+ void saveIfNeccessary();
+
+public slots:
+ void changeOccurred();
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+private:
+ QBasicTimer m_timer;
+ QTime m_firstChange;
+
+};
+
+#endif // AUTOSAVER_H
+
diff --git a/demos/browser/bookmarks.cpp b/demos/browser/bookmarks.cpp
new file mode 100644
index 0000000..8e7823d
--- /dev/null
+++ b/demos/browser/bookmarks.cpp
@@ -0,0 +1,987 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "bookmarks.h"
+
+#include "autosaver.h"
+#include "browserapplication.h"
+#include "history.h"
+#include "xbel.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QFile>
+#include <QtCore/QMimeData>
+
+#include <QtGui/QDesktopServices>
+#include <QtGui/QDragEnterEvent>
+#include <QtGui/QFileDialog>
+#include <QtGui/QHeaderView>
+#include <QtGui/QIcon>
+#include <QtGui/QMessageBox>
+#include <QtGui/QToolButton>
+
+#include <QtWebKit/QWebSettings>
+
+#include <QtCore/QDebug>
+
+#define BOOKMARKBAR "Bookmarks Bar"
+#define BOOKMARKMENU "Bookmarks Menu"
+
+BookmarksManager::BookmarksManager(QObject *parent)
+ : QObject(parent)
+ , m_loaded(false)
+ , m_saveTimer(new AutoSaver(this))
+ , m_bookmarkRootNode(0)
+ , m_bookmarkModel(0)
+{
+ connect(this, SIGNAL(entryAdded(BookmarkNode *)),
+ m_saveTimer, SLOT(changeOccurred()));
+ connect(this, SIGNAL(entryRemoved(BookmarkNode *, int, BookmarkNode *)),
+ m_saveTimer, SLOT(changeOccurred()));
+ connect(this, SIGNAL(entryChanged(BookmarkNode *)),
+ m_saveTimer, SLOT(changeOccurred()));
+}
+
+BookmarksManager::~BookmarksManager()
+{
+ m_saveTimer->saveIfNeccessary();
+}
+
+void BookmarksManager::changeExpanded()
+{
+ m_saveTimer->changeOccurred();
+}
+
+void BookmarksManager::load()
+{
+ if (m_loaded)
+ return;
+ m_loaded = true;
+
+ QString dir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
+ QString bookmarkFile = dir + QLatin1String("/bookmarks.xbel");
+ if (!QFile::exists(bookmarkFile))
+ bookmarkFile = QLatin1String(":defaultbookmarks.xbel");
+
+ XbelReader reader;
+ m_bookmarkRootNode = reader.read(bookmarkFile);
+ if (reader.error() != QXmlStreamReader::NoError) {
+ QMessageBox::warning(0, QLatin1String("Loading Bookmark"),
+ tr("Error when loading bookmarks on line %1, column %2:\n"
+ "%3").arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()));
+ }
+
+ BookmarkNode *toolbar = 0;
+ BookmarkNode *menu = 0;
+ QList<BookmarkNode*> others;
+ for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i) {
+ BookmarkNode *node = m_bookmarkRootNode->children().at(i);
+ if (node->type() == BookmarkNode::Folder) {
+ // Automatically convert
+ if (node->title == tr("Toolbar Bookmarks") && !toolbar) {
+ node->title = tr(BOOKMARKBAR);
+ }
+ if (node->title == tr(BOOKMARKBAR) && !toolbar) {
+ toolbar = node;
+ }
+
+ // Automatically convert
+ if (node->title == tr("Menu") && !menu) {
+ node->title = tr(BOOKMARKMENU);
+ }
+ if (node->title == tr(BOOKMARKMENU) && !menu) {
+ menu = node;
+ }
+ } else {
+ others.append(node);
+ }
+ m_bookmarkRootNode->remove(node);
+ }
+ Q_ASSERT(m_bookmarkRootNode->children().count() == 0);
+ if (!toolbar) {
+ toolbar = new BookmarkNode(BookmarkNode::Folder, m_bookmarkRootNode);
+ toolbar->title = tr(BOOKMARKBAR);
+ } else {
+ m_bookmarkRootNode->add(toolbar);
+ }
+
+ if (!menu) {
+ menu = new BookmarkNode(BookmarkNode::Folder, m_bookmarkRootNode);
+ menu->title = tr(BOOKMARKMENU);
+ } else {
+ m_bookmarkRootNode->add(menu);
+ }
+
+ for (int i = 0; i < others.count(); ++i)
+ menu->add(others.at(i));
+}
+
+void BookmarksManager::save() const
+{
+ if (!m_loaded)
+ return;
+
+ XbelWriter writer;
+ QString dir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
+ QString bookmarkFile = dir + QLatin1String("/bookmarks.xbel");
+ if (!writer.write(bookmarkFile, m_bookmarkRootNode))
+ qWarning() << "BookmarkManager: error saving to" << bookmarkFile;
+}
+
+void BookmarksManager::addBookmark(BookmarkNode *parent, BookmarkNode *node, int row)
+{
+ if (!m_loaded)
+ return;
+ Q_ASSERT(parent);
+ InsertBookmarksCommand *command = new InsertBookmarksCommand(this, parent, node, row);
+ m_commands.push(command);
+}
+
+void BookmarksManager::removeBookmark(BookmarkNode *node)
+{
+ if (!m_loaded)
+ return;
+
+ Q_ASSERT(node);
+ BookmarkNode *parent = node->parent();
+ int row = parent->children().indexOf(node);
+ RemoveBookmarksCommand *command = new RemoveBookmarksCommand(this, parent, row);
+ m_commands.push(command);
+}
+
+void BookmarksManager::setTitle(BookmarkNode *node, const QString &newTitle)
+{
+ if (!m_loaded)
+ return;
+
+ Q_ASSERT(node);
+ ChangeBookmarkCommand *command = new ChangeBookmarkCommand(this, node, newTitle, true);
+ m_commands.push(command);
+}
+
+void BookmarksManager::setUrl(BookmarkNode *node, const QString &newUrl)
+{
+ if (!m_loaded)
+ return;
+
+ Q_ASSERT(node);
+ ChangeBookmarkCommand *command = new ChangeBookmarkCommand(this, node, newUrl, false);
+ m_commands.push(command);
+}
+
+BookmarkNode *BookmarksManager::bookmarks()
+{
+ if (!m_loaded)
+ load();
+ return m_bookmarkRootNode;
+}
+
+BookmarkNode *BookmarksManager::menu()
+{
+ if (!m_loaded)
+ load();
+
+ for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i) {
+ BookmarkNode *node = m_bookmarkRootNode->children().at(i);
+ if (node->title == tr(BOOKMARKMENU))
+ return node;
+ }
+ Q_ASSERT(false);
+ return 0;
+}
+
+BookmarkNode *BookmarksManager::toolbar()
+{
+ if (!m_loaded)
+ load();
+
+ for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i) {
+ BookmarkNode *node = m_bookmarkRootNode->children().at(i);
+ if (node->title == tr(BOOKMARKBAR))
+ return node;
+ }
+ Q_ASSERT(false);
+ return 0;
+}
+
+BookmarksModel *BookmarksManager::bookmarksModel()
+{
+ if (!m_bookmarkModel)
+ m_bookmarkModel = new BookmarksModel(this, this);
+ return m_bookmarkModel;
+}
+
+void BookmarksManager::importBookmarks()
+{
+ QString fileName = QFileDialog::getOpenFileName(0, tr("Open File"),
+ QString(),
+ tr("XBEL (*.xbel *.xml)"));
+ if (fileName.isEmpty())
+ return;
+
+ XbelReader reader;
+ BookmarkNode *importRootNode = reader.read(fileName);
+ if (reader.error() != QXmlStreamReader::NoError) {
+ QMessageBox::warning(0, QLatin1String("Loading Bookmark"),
+ tr("Error when loading bookmarks on line %1, column %2:\n"
+ "%3").arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()));
+ }
+
+ importRootNode->setType(BookmarkNode::Folder);
+ importRootNode->title = (tr("Imported %1").arg(QDate::currentDate().toString(Qt::SystemLocaleShortDate)));
+ addBookmark(menu(), importRootNode);
+}
+
+void BookmarksManager::exportBookmarks()
+{
+ QString fileName = QFileDialog::getSaveFileName(0, tr("Save File"),
+ tr("%1 Bookmarks.xbel").arg(QCoreApplication::applicationName()),
+ tr("XBEL (*.xbel *.xml)"));
+ if (fileName.isEmpty())
+ return;
+
+ XbelWriter writer;
+ if (!writer.write(fileName, m_bookmarkRootNode))
+ QMessageBox::critical(0, tr("Export error"), tr("error saving bookmarks"));
+}
+
+RemoveBookmarksCommand::RemoveBookmarksCommand(BookmarksManager *m_bookmarkManagaer, BookmarkNode *parent, int row)
+ : QUndoCommand(BookmarksManager::tr("Remove Bookmark"))
+ , m_row(row)
+ , m_bookmarkManagaer(m_bookmarkManagaer)
+ , m_node(parent->children().value(row))
+ , m_parent(parent)
+ , m_done(false)
+{
+}
+
+RemoveBookmarksCommand::~RemoveBookmarksCommand()
+{
+ if (m_done && !m_node->parent()) {
+ delete m_node;
+ }
+}
+
+void RemoveBookmarksCommand::undo()
+{
+ m_parent->add(m_node, m_row);
+ emit m_bookmarkManagaer->entryAdded(m_node);
+ m_done = false;
+}
+
+void RemoveBookmarksCommand::redo()
+{
+ m_parent->remove(m_node);
+ emit m_bookmarkManagaer->entryRemoved(m_parent, m_row, m_node);
+ m_done = true;
+}
+
+InsertBookmarksCommand::InsertBookmarksCommand(BookmarksManager *m_bookmarkManagaer,
+ BookmarkNode *parent, BookmarkNode *node, int row)
+ : RemoveBookmarksCommand(m_bookmarkManagaer, parent, row)
+{
+ setText(BookmarksManager::tr("Insert Bookmark"));
+ m_node = node;
+}
+
+ChangeBookmarkCommand::ChangeBookmarkCommand(BookmarksManager *m_bookmarkManagaer, BookmarkNode *node,
+ const QString &newValue, bool title)
+ : QUndoCommand()
+ , m_bookmarkManagaer(m_bookmarkManagaer)
+ , m_title(title)
+ , m_newValue(newValue)
+ , m_node(node)
+{
+ if (m_title) {
+ m_oldValue = m_node->title;
+ setText(BookmarksManager::tr("Name Change"));
+ } else {
+ m_oldValue = m_node->url;
+ setText(BookmarksManager::tr("Address Change"));
+ }
+}
+
+void ChangeBookmarkCommand::undo()
+{
+ if (m_title)
+ m_node->title = m_oldValue;
+ else
+ m_node->url = m_oldValue;
+ emit m_bookmarkManagaer->entryChanged(m_node);
+}
+
+void ChangeBookmarkCommand::redo()
+{
+ if (m_title)
+ m_node->title = m_newValue;
+ else
+ m_node->url = m_newValue;
+ emit m_bookmarkManagaer->entryChanged(m_node);
+}
+
+BookmarksModel::BookmarksModel(BookmarksManager *bookmarkManager, QObject *parent)
+ : QAbstractItemModel(parent)
+ , m_endMacro(false)
+ , m_bookmarksManager(bookmarkManager)
+{
+ connect(bookmarkManager, SIGNAL(entryAdded(BookmarkNode *)),
+ this, SLOT(entryAdded(BookmarkNode *)));
+ connect(bookmarkManager, SIGNAL(entryRemoved(BookmarkNode *, int, BookmarkNode *)),
+ this, SLOT(entryRemoved(BookmarkNode *, int, BookmarkNode *)));
+ connect(bookmarkManager, SIGNAL(entryChanged(BookmarkNode *)),
+ this, SLOT(entryChanged(BookmarkNode *)));
+}
+
+QModelIndex BookmarksModel::index(BookmarkNode *node) const
+{
+ BookmarkNode *parent = node->parent();
+ if (!parent)
+ return QModelIndex();
+ return createIndex(parent->children().indexOf(node), 0, node);
+}
+
+void BookmarksModel::entryAdded(BookmarkNode *item)
+{
+ Q_ASSERT(item && item->parent());
+ int row = item->parent()->children().indexOf(item);
+ BookmarkNode *parent = item->parent();
+ // item was already added so remove beore beginInsertRows is called
+ parent->remove(item);
+ beginInsertRows(index(parent), row, row);
+ parent->add(item, row);
+ endInsertRows();
+}
+
+void BookmarksModel::entryRemoved(BookmarkNode *parent, int row, BookmarkNode *item)
+{
+ // item was already removed, re-add so beginRemoveRows works
+ parent->add(item, row);
+ beginRemoveRows(index(parent), row, row);
+ parent->remove(item);
+ endRemoveRows();
+}
+
+void BookmarksModel::entryChanged(BookmarkNode *item)
+{
+ QModelIndex idx = index(item);
+ emit dataChanged(idx, idx);
+}
+
+bool BookmarksModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (row < 0 || count <= 0 || row + count > rowCount(parent))
+ return false;
+
+ BookmarkNode *bookmarkNode = node(parent);
+ for (int i = row + count - 1; i >= row; --i) {
+ BookmarkNode *node = bookmarkNode->children().at(i);
+ if (node == m_bookmarksManager->menu()
+ || node == m_bookmarksManager->toolbar())
+ continue;
+
+ m_bookmarksManager->removeBookmark(node);
+ }
+ if (m_endMacro) {
+ m_bookmarksManager->undoRedoStack()->endMacro();
+ m_endMacro = false;
+ }
+ return true;
+}
+
+QVariant BookmarksModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+ switch (section) {
+ case 0: return tr("Title");
+ case 1: return tr("Address");
+ }
+ }
+ return QAbstractItemModel::headerData(section, orientation, role);
+}
+
+QVariant BookmarksModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.model() != this)
+ return QVariant();
+
+ const BookmarkNode *bookmarkNode = node(index);
+ switch (role) {
+ case Qt::EditRole:
+ case Qt::DisplayRole:
+ if (bookmarkNode->type() == BookmarkNode::Separator) {
+ switch (index.column()) {
+ case 0: return QString(50, 0xB7);
+ case 1: return QString();
+ }
+ }
+
+ switch (index.column()) {
+ case 0: return bookmarkNode->title;
+ case 1: return bookmarkNode->url;
+ }
+ break;
+ case BookmarksModel::UrlRole:
+ return QUrl(bookmarkNode->url);
+ break;
+ case BookmarksModel::UrlStringRole:
+ return bookmarkNode->url;
+ break;
+ case BookmarksModel::TypeRole:
+ return bookmarkNode->type();
+ break;
+ case BookmarksModel::SeparatorRole:
+ return (bookmarkNode->type() == BookmarkNode::Separator);
+ break;
+ case Qt::DecorationRole:
+ if (index.column() == 0) {
+ if (bookmarkNode->type() == BookmarkNode::Folder)
+ return QApplication::style()->standardIcon(QStyle::SP_DirIcon);
+ return BrowserApplication::instance()->icon(bookmarkNode->url);
+ }
+ }
+
+ return QVariant();
+}
+
+int BookmarksModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.column() > 0) ? 0 : 2;
+}
+
+int BookmarksModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.column() > 0)
+ return 0;
+
+ if (!parent.isValid())
+ return m_bookmarksManager->bookmarks()->children().count();
+
+ const BookmarkNode *item = static_cast<BookmarkNode*>(parent.internalPointer());
+ return item->children().count();
+}
+
+QModelIndex BookmarksModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (row < 0 || column < 0 || row >= rowCount(parent) || column >= columnCount(parent))
+ return QModelIndex();
+
+ // get the parent node
+ BookmarkNode *parentNode = node(parent);
+ return createIndex(row, column, parentNode->children().at(row));
+}
+
+QModelIndex BookmarksModel::parent(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QModelIndex();
+
+ BookmarkNode *itemNode = node(index);
+ BookmarkNode *parentNode = (itemNode ? itemNode->parent() : 0);
+ if (!parentNode || parentNode == m_bookmarksManager->bookmarks())
+ return QModelIndex();
+
+ // get the parent's row
+ BookmarkNode *grandParentNode = parentNode->parent();
+ int parentRow = grandParentNode->children().indexOf(parentNode);
+ Q_ASSERT(parentRow >= 0);
+ return createIndex(parentRow, 0, parentNode);
+}
+
+bool BookmarksModel::hasChildren(const QModelIndex &parent) const
+{
+ if (!parent.isValid())
+ return true;
+ const BookmarkNode *parentNode = node(parent);
+ return (parentNode->type() == BookmarkNode::Folder);
+}
+
+Qt::ItemFlags BookmarksModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+
+ Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+
+ BookmarkNode *bookmarkNode = node(index);
+
+ if (bookmarkNode != m_bookmarksManager->menu()
+ && bookmarkNode != m_bookmarksManager->toolbar()) {
+ flags |= Qt::ItemIsDragEnabled;
+ if (bookmarkNode->type() != BookmarkNode::Separator)
+ flags |= Qt::ItemIsEditable;
+ }
+ if (hasChildren(index))
+ flags |= Qt::ItemIsDropEnabled;
+ return flags;
+}
+
+Qt::DropActions BookmarksModel::supportedDropActions () const
+{
+ return Qt::CopyAction | Qt::MoveAction;
+}
+
+#define MIMETYPE QLatin1String("application/bookmarks.xbel")
+
+QStringList BookmarksModel::mimeTypes() const
+{
+ QStringList types;
+ types << MIMETYPE;
+ return types;
+}
+
+QMimeData *BookmarksModel::mimeData(const QModelIndexList &indexes) const
+{
+ QMimeData *mimeData = new QMimeData();
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+ foreach (QModelIndex index, indexes) {
+ if (index.column() != 0 || !index.isValid())
+ continue;
+ QByteArray encodedData;
+ QBuffer buffer(&encodedData);
+ buffer.open(QBuffer::ReadWrite);
+ XbelWriter writer;
+ const BookmarkNode *parentNode = node(index);
+ writer.write(&buffer, parentNode);
+ stream << encodedData;
+ }
+ mimeData->setData(MIMETYPE, data);
+ return mimeData;
+}
+
+bool BookmarksModel::dropMimeData(const QMimeData *data,
+ Qt::DropAction action, int row, int column, const QModelIndex &parent)
+{
+ if (action == Qt::IgnoreAction)
+ return true;
+
+ if (!data->hasFormat(MIMETYPE)
+ || column > 0)
+ return false;
+
+ QByteArray ba = data->data(MIMETYPE);
+ QDataStream stream(&ba, QIODevice::ReadOnly);
+ if (stream.atEnd())
+ return false;
+
+ QUndoStack *undoStack = m_bookmarksManager->undoRedoStack();
+ undoStack->beginMacro(QLatin1String("Move Bookmarks"));
+
+ while (!stream.atEnd()) {
+ QByteArray encodedData;
+ stream >> encodedData;
+ QBuffer buffer(&encodedData);
+ buffer.open(QBuffer::ReadOnly);
+
+ XbelReader reader;
+ BookmarkNode *rootNode = reader.read(&buffer);
+ QList<BookmarkNode*> children = rootNode->children();
+ for (int i = 0; i < children.count(); ++i) {
+ BookmarkNode *bookmarkNode = children.at(i);
+ rootNode->remove(bookmarkNode);
+ row = qMax(0, row);
+ BookmarkNode *parentNode = node(parent);
+ m_bookmarksManager->addBookmark(parentNode, bookmarkNode, row);
+ m_endMacro = true;
+ }
+ delete rootNode;
+ }
+ return true;
+}
+
+bool BookmarksModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!index.isValid() || (flags(index) & Qt::ItemIsEditable) == 0)
+ return false;
+
+ BookmarkNode *item = node(index);
+
+ switch (role) {
+ case Qt::EditRole:
+ case Qt::DisplayRole:
+ if (index.column() == 0) {
+ m_bookmarksManager->setTitle(item, value.toString());
+ break;
+ }
+ if (index.column() == 1) {
+ m_bookmarksManager->setUrl(item, value.toString());
+ break;
+ }
+ return false;
+ case BookmarksModel::UrlRole:
+ m_bookmarksManager->setUrl(item, value.toUrl().toString());
+ break;
+ case BookmarksModel::UrlStringRole:
+ m_bookmarksManager->setUrl(item, value.toString());
+ break;
+ default:
+ break;
+ return false;
+ }
+
+ return true;
+}
+
+BookmarkNode *BookmarksModel::node(const QModelIndex &index) const
+{
+ BookmarkNode *itemNode = static_cast<BookmarkNode*>(index.internalPointer());
+ if (!itemNode)
+ return m_bookmarksManager->bookmarks();
+ return itemNode;
+}
+
+
+AddBookmarkProxyModel::AddBookmarkProxyModel(QObject *parent)
+ : QSortFilterProxyModel(parent)
+{
+}
+
+int AddBookmarkProxyModel::columnCount(const QModelIndex &parent) const
+{
+ return qMin(1, QSortFilterProxyModel::columnCount(parent));
+}
+
+bool AddBookmarkProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+ QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
+ return sourceModel()->hasChildren(idx);
+}
+
+AddBookmarkDialog::AddBookmarkDialog(const QString &url, const QString &title, QWidget *parent, BookmarksManager *bookmarkManager)
+ : QDialog(parent)
+ , m_url(url)
+ , m_bookmarksManager(bookmarkManager)
+{
+ setWindowFlags(Qt::Sheet);
+ if (!m_bookmarksManager)
+ m_bookmarksManager = BrowserApplication::bookmarksManager();
+ setupUi(this);
+ QTreeView *view = new QTreeView(this);
+ m_proxyModel = new AddBookmarkProxyModel(this);
+ BookmarksModel *model = m_bookmarksManager->bookmarksModel();
+ m_proxyModel->setSourceModel(model);
+ view->setModel(m_proxyModel);
+ view->expandAll();
+ view->header()->setStretchLastSection(true);
+ view->header()->hide();
+ view->setItemsExpandable(false);
+ view->setRootIsDecorated(false);
+ view->setIndentation(10);
+ location->setModel(m_proxyModel);
+ view->show();
+ location->setView(view);
+ BookmarkNode *menu = m_bookmarksManager->menu();
+ QModelIndex idx = m_proxyModel->mapFromSource(model->index(menu));
+ view->setCurrentIndex(idx);
+ location->setCurrentIndex(idx.row());
+ name->setText(title);
+}
+
+void AddBookmarkDialog::accept()
+{
+ QModelIndex index = location->view()->currentIndex();
+ index = m_proxyModel->mapToSource(index);
+ if (!index.isValid())
+ index = m_bookmarksManager->bookmarksModel()->index(0, 0);
+ BookmarkNode *parent = m_bookmarksManager->bookmarksModel()->node(index);
+ BookmarkNode *bookmark = new BookmarkNode(BookmarkNode::Bookmark);
+ bookmark->url = m_url;
+ bookmark->title = name->text();
+ m_bookmarksManager->addBookmark(parent, bookmark);
+ QDialog::accept();
+}
+
+BookmarksMenu::BookmarksMenu(QWidget *parent)
+ : ModelMenu(parent)
+ , m_bookmarksManager(0)
+{
+ connect(this, SIGNAL(activated(const QModelIndex &)),
+ this, SLOT(activated(const QModelIndex &)));
+ setMaxRows(-1);
+ setHoverRole(BookmarksModel::UrlStringRole);
+ setSeparatorRole(BookmarksModel::SeparatorRole);
+}
+
+void BookmarksMenu::activated(const QModelIndex &index)
+{
+ emit openUrl(index.data(BookmarksModel::UrlRole).toUrl());
+}
+
+bool BookmarksMenu::prePopulated()
+{
+ m_bookmarksManager = BrowserApplication::bookmarksManager();
+ setModel(m_bookmarksManager->bookmarksModel());
+ setRootIndex(m_bookmarksManager->bookmarksModel()->index(1, 0));
+ // initial actions
+ for (int i = 0; i < m_initialActions.count(); ++i)
+ addAction(m_initialActions.at(i));
+ if (!m_initialActions.isEmpty())
+ addSeparator();
+ createMenu(model()->index(0, 0), 1, this);
+ return true;
+}
+
+void BookmarksMenu::setInitialActions(QList<QAction*> actions)
+{
+ m_initialActions = actions;
+ for (int i = 0; i < m_initialActions.count(); ++i)
+ addAction(m_initialActions.at(i));
+}
+
+BookmarksDialog::BookmarksDialog(QWidget *parent, BookmarksManager *manager)
+ : QDialog(parent)
+{
+ m_bookmarksManager = manager;
+ if (!m_bookmarksManager)
+ m_bookmarksManager = BrowserApplication::bookmarksManager();
+ setupUi(this);
+
+ tree->setUniformRowHeights(true);
+ tree->setSelectionBehavior(QAbstractItemView::SelectRows);
+ tree->setSelectionMode(QAbstractItemView::ContiguousSelection);
+ tree->setTextElideMode(Qt::ElideMiddle);
+ m_bookmarksModel = m_bookmarksManager->bookmarksModel();
+ m_proxyModel = new TreeProxyModel(this);
+ connect(search, SIGNAL(textChanged(QString)),
+ m_proxyModel, SLOT(setFilterFixedString(QString)));
+ connect(removeButton, SIGNAL(clicked()), tree, SLOT(removeOne()));
+ m_proxyModel->setSourceModel(m_bookmarksModel);
+ tree->setModel(m_proxyModel);
+ tree->setDragDropMode(QAbstractItemView::InternalMove);
+ tree->setExpanded(m_proxyModel->index(0, 0), true);
+ tree->setAlternatingRowColors(true);
+ QFontMetrics fm(font());
+ int header = fm.width(QLatin1Char('m')) * 40;
+ tree->header()->resizeSection(0, header);
+ tree->header()->setStretchLastSection(true);
+ connect(tree, SIGNAL(activated(const QModelIndex&)),
+ this, SLOT(open()));
+ tree->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(tree, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(customContextMenuRequested(const QPoint &)));
+ connect(addFolderButton, SIGNAL(clicked()),
+ this, SLOT(newFolder()));
+ expandNodes(m_bookmarksManager->bookmarks());
+ setAttribute(Qt::WA_DeleteOnClose);
+}
+
+BookmarksDialog::~BookmarksDialog()
+{
+ if (saveExpandedNodes(tree->rootIndex()))
+ m_bookmarksManager->changeExpanded();
+}
+
+bool BookmarksDialog::saveExpandedNodes(const QModelIndex &parent)
+{
+ bool changed = false;
+ for (int i = 0; i < m_proxyModel->rowCount(parent); ++i) {
+ QModelIndex child = m_proxyModel->index(i, 0, parent);
+ QModelIndex sourceIndex = m_proxyModel->mapToSource(child);
+ BookmarkNode *childNode = m_bookmarksModel->node(sourceIndex);
+ bool wasExpanded = childNode->expanded;
+ if (tree->isExpanded(child)) {
+ childNode->expanded = true;
+ changed |= saveExpandedNodes(child);
+ } else {
+ childNode->expanded = false;
+ }
+ changed |= (wasExpanded != childNode->expanded);
+ }
+ return changed;
+}
+
+void BookmarksDialog::expandNodes(BookmarkNode *node)
+{
+ for (int i = 0; i < node->children().count(); ++i) {
+ BookmarkNode *childNode = node->children()[i];
+ if (childNode->expanded) {
+ QModelIndex idx = m_bookmarksModel->index(childNode);
+ idx = m_proxyModel->mapFromSource(idx);
+ tree->setExpanded(idx, true);
+ expandNodes(childNode);
+ }
+ }
+}
+
+void BookmarksDialog::customContextMenuRequested(const QPoint &pos)
+{
+ QMenu menu;
+ QModelIndex index = tree->indexAt(pos);
+ index = index.sibling(index.row(), 0);
+ if (index.isValid() && !tree->model()->hasChildren(index)) {
+ menu.addAction(tr("Open"), this, SLOT(open()));
+ menu.addSeparator();
+ }
+ menu.addAction(tr("Delete"), tree, SLOT(removeOne()));
+ menu.exec(QCursor::pos());
+}
+
+void BookmarksDialog::open()
+{
+ QModelIndex index = tree->currentIndex();
+ if (!index.parent().isValid())
+ return;
+ emit openUrl(index.sibling(index.row(), 1).data(BookmarksModel::UrlRole).toUrl());
+}
+
+void BookmarksDialog::newFolder()
+{
+ QModelIndex currentIndex = tree->currentIndex();
+ QModelIndex idx = currentIndex;
+ if (idx.isValid() && !idx.model()->hasChildren(idx))
+ idx = idx.parent();
+ if (!idx.isValid())
+ idx = tree->rootIndex();
+ idx = m_proxyModel->mapToSource(idx);
+ BookmarkNode *parent = m_bookmarksManager->bookmarksModel()->node(idx);
+ BookmarkNode *node = new BookmarkNode(BookmarkNode::Folder);
+ node->title = tr("New Folder");
+ m_bookmarksManager->addBookmark(parent, node, currentIndex.row() + 1);
+}
+
+BookmarksToolBar::BookmarksToolBar(BookmarksModel *model, QWidget *parent)
+ : QToolBar(tr("Bookmark"), parent)
+ , m_bookmarksModel(model)
+{
+ connect(this, SIGNAL(actionTriggered(QAction*)), this, SLOT(triggered(QAction*)));
+ setRootIndex(model->index(0, 0));
+ connect(m_bookmarksModel, SIGNAL(modelReset()), this, SLOT(build()));
+ connect(m_bookmarksModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(build()));
+ connect(m_bookmarksModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SLOT(build()));
+ connect(m_bookmarksModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(build()));
+ setAcceptDrops(true);
+}
+
+void BookmarksToolBar::dragEnterEvent(QDragEnterEvent *event)
+{
+ const QMimeData *mimeData = event->mimeData();
+ if (mimeData->hasUrls())
+ event->acceptProposedAction();
+ QToolBar::dragEnterEvent(event);
+}
+
+void BookmarksToolBar::dropEvent(QDropEvent *event)
+{
+ const QMimeData *mimeData = event->mimeData();
+ if (mimeData->hasUrls() && mimeData->hasText()) {
+ QList<QUrl> urls = mimeData->urls();
+ QAction *action = actionAt(event->pos());
+ QString dropText;
+ if (action)
+ dropText = action->text();
+ int row = -1;
+ QModelIndex parentIndex = m_root;
+ for (int i = 0; i < m_bookmarksModel->rowCount(m_root); ++i) {
+ QModelIndex idx = m_bookmarksModel->index(i, 0, m_root);
+ QString title = idx.data().toString();
+ if (title == dropText) {
+ row = i;
+ if (m_bookmarksModel->hasChildren(idx)) {
+ parentIndex = idx;
+ row = -1;
+ }
+ break;
+ }
+ }
+ BookmarkNode *bookmark = new BookmarkNode(BookmarkNode::Bookmark);
+ bookmark->url = urls.at(0).toString();
+ bookmark->title = mimeData->text();
+
+ BookmarkNode *parent = m_bookmarksModel->node(parentIndex);
+ BookmarksManager *bookmarksManager = m_bookmarksModel->bookmarksManager();
+ bookmarksManager->addBookmark(parent, bookmark, row);
+ event->acceptProposedAction();
+ }
+ QToolBar::dropEvent(event);
+}
+
+
+void BookmarksToolBar::setRootIndex(const QModelIndex &index)
+{
+ m_root = index;
+ build();
+}
+
+QModelIndex BookmarksToolBar::rootIndex() const
+{
+ return m_root;
+}
+
+void BookmarksToolBar::build()
+{
+ clear();
+ for (int i = 0; i < m_bookmarksModel->rowCount(m_root); ++i) {
+ QModelIndex idx = m_bookmarksModel->index(i, 0, m_root);
+ if (m_bookmarksModel->hasChildren(idx)) {
+ QToolButton *button = new QToolButton(this);
+ button->setPopupMode(QToolButton::InstantPopup);
+ button->setArrowType(Qt::DownArrow);
+ button->setText(idx.data().toString());
+ ModelMenu *menu = new ModelMenu(this);
+ connect(menu, SIGNAL(activated(const QModelIndex &)),
+ this, SLOT(activated(const QModelIndex &)));
+ menu->setModel(m_bookmarksModel);
+ menu->setRootIndex(idx);
+ menu->addAction(new QAction(menu));
+ button->setMenu(menu);
+ button->setToolButtonStyle(Qt::ToolButtonTextOnly);
+ QAction *a = addWidget(button);
+ a->setText(idx.data().toString());
+ } else {
+ QAction *action = addAction(idx.data().toString());
+ action->setData(idx.data(BookmarksModel::UrlRole));
+ }
+ }
+}
+
+void BookmarksToolBar::triggered(QAction *action)
+{
+ QVariant v = action->data();
+ if (v.canConvert<QUrl>()) {
+ emit openUrl(v.toUrl());
+ }
+}
+
+void BookmarksToolBar::activated(const QModelIndex &index)
+{
+ emit openUrl(index.data(BookmarksModel::UrlRole).toUrl());
+}
+
diff --git a/demos/browser/bookmarks.h b/demos/browser/bookmarks.h
new file mode 100644
index 0000000..fb47b4f
--- /dev/null
+++ b/demos/browser/bookmarks.h
@@ -0,0 +1,310 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BOOKMARKS_H
+#define BOOKMARKS_H
+
+#include <QtCore/QObject>
+#include <QtCore/QAbstractItemModel>
+
+#include <QtGui/QUndoCommand>
+
+/*!
+ Bookmark manager, owner of the bookmarks, loads, saves and basic tasks
+ */
+class AutoSaver;
+class BookmarkNode;
+class BookmarksModel;
+class BookmarksManager : public QObject
+{
+ Q_OBJECT
+
+signals:
+ void entryAdded(BookmarkNode *item);
+ void entryRemoved(BookmarkNode *parent, int row, BookmarkNode *item);
+ void entryChanged(BookmarkNode *item);
+
+public:
+ BookmarksManager(QObject *parent = 0);
+ ~BookmarksManager();
+
+ void addBookmark(BookmarkNode *parent, BookmarkNode *node, int row = -1);
+ void removeBookmark(BookmarkNode *node);
+ void setTitle(BookmarkNode *node, const QString &newTitle);
+ void setUrl(BookmarkNode *node, const QString &newUrl);
+ void changeExpanded();
+
+ BookmarkNode *bookmarks();
+ BookmarkNode *menu();
+ BookmarkNode *toolbar();
+
+ BookmarksModel *bookmarksModel();
+ QUndoStack *undoRedoStack() { return &m_commands; };
+
+public slots:
+ void importBookmarks();
+ void exportBookmarks();
+
+private slots:
+ void save() const;
+
+private:
+ void load();
+
+ bool m_loaded;
+ AutoSaver *m_saveTimer;
+ BookmarkNode *m_bookmarkRootNode;
+ BookmarksModel *m_bookmarkModel;
+ QUndoStack m_commands;
+
+ friend class RemoveBookmarksCommand;
+ friend class ChangeBookmarkCommand;
+};
+
+class RemoveBookmarksCommand : public QUndoCommand
+{
+
+public:
+ RemoveBookmarksCommand(BookmarksManager *m_bookmarkManagaer, BookmarkNode *parent, int row);
+ ~RemoveBookmarksCommand();
+ void undo();
+ void redo();
+
+protected:
+ int m_row;
+ BookmarksManager *m_bookmarkManagaer;
+ BookmarkNode *m_node;
+ BookmarkNode *m_parent;
+ bool m_done;
+};
+
+class InsertBookmarksCommand : public RemoveBookmarksCommand
+{
+
+public:
+ InsertBookmarksCommand(BookmarksManager *m_bookmarkManagaer,
+ BookmarkNode *parent, BookmarkNode *node, int row);
+ void undo() { RemoveBookmarksCommand::redo(); }
+ void redo() { RemoveBookmarksCommand::undo(); }
+
+};
+
+class ChangeBookmarkCommand : public QUndoCommand
+{
+
+public:
+ ChangeBookmarkCommand(BookmarksManager *m_bookmarkManagaer,
+ BookmarkNode *node, const QString &newValue, bool title);
+ void undo();
+ void redo();
+
+private:
+ BookmarksManager *m_bookmarkManagaer;
+ bool m_title;
+ QString m_oldValue;
+ QString m_newValue;
+ BookmarkNode *m_node;
+};
+
+/*!
+ BookmarksModel is a QAbstractItemModel wrapper around the BookmarkManager
+ */
+#include <QtGui/QIcon>
+class BookmarksModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public slots:
+ void entryAdded(BookmarkNode *item);
+ void entryRemoved(BookmarkNode *parent, int row, BookmarkNode *item);
+ void entryChanged(BookmarkNode *item);
+
+public:
+ enum Roles {
+ TypeRole = Qt::UserRole + 1,
+ UrlRole = Qt::UserRole + 2,
+ UrlStringRole = Qt::UserRole + 3,
+ SeparatorRole = Qt::UserRole + 4
+ };
+
+ BookmarksModel(BookmarksManager *bookmarkManager, QObject *parent = 0);
+ inline BookmarksManager *bookmarksManager() const { return m_bookmarksManager; }
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex index(int, int, const QModelIndex& = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex& index= QModelIndex()) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ Qt::DropActions supportedDropActions () const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ QMimeData *mimeData(const QModelIndexList &indexes) const;
+ QStringList mimeTypes() const;
+ bool dropMimeData(const QMimeData *data,
+ Qt::DropAction action, int row, int column, const QModelIndex &parent);
+ bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
+
+ BookmarkNode *node(const QModelIndex &index) const;
+ QModelIndex index(BookmarkNode *node) const;
+
+private:
+
+ bool m_endMacro;
+ BookmarksManager *m_bookmarksManager;
+};
+
+// Menu that is dynamically populated from the bookmarks
+#include "modelmenu.h"
+class BookmarksMenu : public ModelMenu
+{
+ Q_OBJECT
+
+signals:
+ void openUrl(const QUrl &url);
+
+public:
+ BookmarksMenu(QWidget *parent = 0);
+ void setInitialActions(QList<QAction*> actions);
+
+protected:
+ bool prePopulated();
+
+private slots:
+ void activated(const QModelIndex &index);
+
+private:
+ BookmarksManager *m_bookmarksManager;
+ QList<QAction*> m_initialActions;
+};
+
+/*
+ Proxy model that filters out the bookmarks so only the folders
+ are left behind. Used in the add bookmark dialog combobox.
+ */
+#include <QtGui/QSortFilterProxyModel>
+class AddBookmarkProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ AddBookmarkProxyModel(QObject * parent = 0);
+ int columnCount(const QModelIndex & parent = QModelIndex()) const;
+
+protected:
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
+};
+
+/*!
+ Add bookmark dialog
+ */
+#include "ui_addbookmarkdialog.h"
+class AddBookmarkDialog : public QDialog, public Ui_AddBookmarkDialog
+{
+ Q_OBJECT
+
+public:
+ AddBookmarkDialog(const QString &url, const QString &title, QWidget *parent = 0, BookmarksManager *bookmarkManager = 0);
+
+private slots:
+ void accept();
+
+private:
+ QString m_url;
+ BookmarksManager *m_bookmarksManager;
+ AddBookmarkProxyModel *m_proxyModel;
+};
+
+#include "ui_bookmarks.h"
+class TreeProxyModel;
+class BookmarksDialog : public QDialog, public Ui_BookmarksDialog
+{
+ Q_OBJECT
+
+signals:
+ void openUrl(const QUrl &url);
+
+public:
+ BookmarksDialog(QWidget *parent = 0, BookmarksManager *manager = 0);
+ ~BookmarksDialog();
+
+private slots:
+ void customContextMenuRequested(const QPoint &pos);
+ void open();
+ void newFolder();
+
+private:
+ void expandNodes(BookmarkNode *node);
+ bool saveExpandedNodes(const QModelIndex &parent);
+
+ BookmarksManager *m_bookmarksManager;
+ BookmarksModel *m_bookmarksModel;
+ TreeProxyModel *m_proxyModel;
+};
+
+#include <QtGui/QToolBar>
+class BookmarksToolBar : public QToolBar
+{
+ Q_OBJECT
+
+signals:
+ void openUrl(const QUrl &url);
+
+public:
+ BookmarksToolBar(BookmarksModel *model, QWidget *parent = 0);
+ void setRootIndex(const QModelIndex &index);
+ QModelIndex rootIndex() const;
+
+protected:
+ void dragEnterEvent(QDragEnterEvent *event);
+ void dropEvent(QDropEvent *event);
+
+private slots:
+ void triggered(QAction *action);
+ void activated(const QModelIndex &index);
+ void build();
+
+private:
+ BookmarksModel *m_bookmarksModel;
+ QPersistentModelIndex m_root;
+};
+
+#endif // BOOKMARKS_H
diff --git a/demos/browser/bookmarks.ui b/demos/browser/bookmarks.ui
new file mode 100644
index 0000000..c893e94
--- /dev/null
+++ b/demos/browser/bookmarks.ui
@@ -0,0 +1,106 @@
+<ui version="4.0" >
+ <class>BookmarksDialog</class>
+ <widget class="QDialog" name="BookmarksDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>758</width>
+ <height>450</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Bookmarks</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>252</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1" >
+ <widget class="SearchLineEdit" name="search" />
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="EditTreeView" name="tree" />
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QPushButton" name="removeButton" >
+ <property name="text" >
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="addFolderButton" >
+ <property name="text" >
+ <string>Add Folder</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>SearchLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>searchlineedit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>EditTreeView</class>
+ <extends>QTreeView</extends>
+ <header>edittreeview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>BookmarksDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>472</x>
+ <y>329</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>461</x>
+ <y>356</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/demos/browser/browser.icns b/demos/browser/browser.icns
new file mode 100644
index 0000000..f591ae4
--- /dev/null
+++ b/demos/browser/browser.icns
Binary files differ
diff --git a/demos/browser/browser.ico b/demos/browser/browser.ico
new file mode 100644
index 0000000..7f9be93
--- /dev/null
+++ b/demos/browser/browser.ico
Binary files differ
diff --git a/demos/browser/browser.pro b/demos/browser/browser.pro
new file mode 100644
index 0000000..c500788
--- /dev/null
+++ b/demos/browser/browser.pro
@@ -0,0 +1,93 @@
+TEMPLATE = app
+TARGET = browser
+QT += webkit network
+
+CONFIG += qt warn_on
+contains(QT_BUILD_PARTS, tools): CONFIG += uitools
+else: DEFINES += QT_NO_UITOOLS
+
+FORMS += \
+ addbookmarkdialog.ui \
+ bookmarks.ui \
+ cookies.ui \
+ cookiesexceptions.ui \
+ downloaditem.ui \
+ downloads.ui \
+ history.ui \
+ passworddialog.ui \
+ proxy.ui \
+ settings.ui
+
+HEADERS += \
+ autosaver.h \
+ bookmarks.h \
+ browserapplication.h \
+ browsermainwindow.h \
+ chasewidget.h \
+ cookiejar.h \
+ downloadmanager.h \
+ edittableview.h \
+ edittreeview.h \
+ history.h \
+ modelmenu.h \
+ networkaccessmanager.h \
+ searchlineedit.h \
+ settings.h \
+ squeezelabel.h \
+ tabwidget.h \
+ toolbarsearch.h \
+ urllineedit.h \
+ webview.h \
+ xbel.h
+
+SOURCES += \
+ autosaver.cpp \
+ bookmarks.cpp \
+ browserapplication.cpp \
+ browsermainwindow.cpp \
+ chasewidget.cpp \
+ cookiejar.cpp \
+ downloadmanager.cpp \
+ edittableview.cpp \
+ edittreeview.cpp \
+ history.cpp \
+ modelmenu.cpp \
+ networkaccessmanager.cpp \
+ searchlineedit.cpp \
+ settings.cpp \
+ squeezelabel.cpp \
+ tabwidget.cpp \
+ toolbarsearch.cpp \
+ urllineedit.cpp \
+ webview.cpp \
+ xbel.cpp \
+ main.cpp
+
+RESOURCES += data/data.qrc htmls/htmls.qrc
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+win32 {
+ RC_FILE = browser.rc
+}
+
+mac {
+ ICON = browser.icns
+ QMAKE_INFO_PLIST = Info_mac.plist
+ TARGET = Browser
+}
+
+wince*: {
+ DEPLOYMENT_PLUGIN += qjpeg qgif
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/browser
+sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS *.plist *.icns *.ico *.rc *.pro *.html *.doc images htmls
+sources.path = $$[QT_INSTALL_DEMOS]/browser
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
diff --git a/demos/browser/browser.rc b/demos/browser/browser.rc
new file mode 100644
index 0000000..89a237c
--- /dev/null
+++ b/demos/browser/browser.rc
@@ -0,0 +1,2 @@
+IDI_ICON1 ICON DISCARDABLE "browser.ico"
+
diff --git a/demos/browser/browserapplication.cpp b/demos/browser/browserapplication.cpp
new file mode 100644
index 0000000..5433022
--- /dev/null
+++ b/demos/browser/browserapplication.cpp
@@ -0,0 +1,456 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "browserapplication.h"
+
+#include "bookmarks.h"
+#include "browsermainwindow.h"
+#include "cookiejar.h"
+#include "downloadmanager.h"
+#include "history.h"
+#include "networkaccessmanager.h"
+#include "tabwidget.h"
+#include "webview.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QDir>
+#include <QtCore/QLibraryInfo>
+#include <QtCore/QSettings>
+#include <QtCore/QTextStream>
+#include <QtCore/QTranslator>
+
+#include <QtGui/QDesktopServices>
+#include <QtGui/QFileOpenEvent>
+#include <QtGui/QMessageBox>
+
+#include <QtNetwork/QLocalServer>
+#include <QtNetwork/QLocalSocket>
+#include <QtNetwork/QNetworkProxy>
+#include <QtNetwork/QSslSocket>
+
+#include <QtWebKit/QWebSettings>
+
+#include <QtCore/QDebug>
+
+DownloadManager *BrowserApplication::s_downloadManager = 0;
+HistoryManager *BrowserApplication::s_historyManager = 0;
+NetworkAccessManager *BrowserApplication::s_networkAccessManager = 0;
+BookmarksManager *BrowserApplication::s_bookmarksManager = 0;
+
+BrowserApplication::BrowserApplication(int &argc, char **argv)
+ : QApplication(argc, argv)
+ , m_localServer(0)
+{
+ QCoreApplication::setOrganizationName(QLatin1String("Trolltech"));
+ QCoreApplication::setApplicationName(QLatin1String("demobrowser"));
+ QCoreApplication::setApplicationVersion(QLatin1String("0.1"));
+#ifdef Q_WS_QWS
+ // Use a different server name for QWS so we can run an X11
+ // browser and a QWS browser in parallel on the same machine for
+ // debugging
+ QString serverName = QCoreApplication::applicationName() + QLatin1String("_qws");
+#else
+ QString serverName = QCoreApplication::applicationName();
+#endif
+ QLocalSocket socket;
+ socket.connectToServer(serverName);
+ if (socket.waitForConnected(500)) {
+ QTextStream stream(&socket);
+ QStringList args = QCoreApplication::arguments();
+ if (args.count() > 1)
+ stream << args.last();
+ else
+ stream << QString();
+ stream.flush();
+ socket.waitForBytesWritten();
+ return;
+ }
+
+#if defined(Q_WS_MAC)
+ QApplication::setQuitOnLastWindowClosed(false);
+#else
+ QApplication::setQuitOnLastWindowClosed(true);
+#endif
+
+ m_localServer = new QLocalServer(this);
+ connect(m_localServer, SIGNAL(newConnection()),
+ this, SLOT(newLocalSocketConnection()));
+ if (!m_localServer->listen(serverName)) {
+ if (m_localServer->serverError() == QAbstractSocket::AddressInUseError
+ && QFile::exists(m_localServer->serverName())) {
+ QFile::remove(m_localServer->serverName());
+ m_localServer->listen(serverName);
+ }
+ }
+
+#ifndef QT_NO_OPENSSL
+ if (!QSslSocket::supportsSsl()) {
+ QMessageBox::information(0, "Demo Browser",
+ "This system does not support OpenSSL. SSL websites will not be available.");
+ }
+#endif
+
+ QDesktopServices::setUrlHandler(QLatin1String("http"), this, "openUrl");
+ QString localSysName = QLocale::system().name();
+
+ installTranslator(QLatin1String("qt_") + localSysName);
+
+ QSettings settings;
+ settings.beginGroup(QLatin1String("sessions"));
+ m_lastSession = settings.value(QLatin1String("lastSession")).toByteArray();
+ settings.endGroup();
+
+#if defined(Q_WS_MAC)
+ connect(this, SIGNAL(lastWindowClosed()),
+ this, SLOT(lastWindowClosed()));
+#endif
+
+ QTimer::singleShot(0, this, SLOT(postLaunch()));
+}
+
+BrowserApplication::~BrowserApplication()
+{
+ delete s_downloadManager;
+ for (int i = 0; i < m_mainWindows.size(); ++i) {
+ BrowserMainWindow *window = m_mainWindows.at(i);
+ delete window;
+ }
+ delete s_networkAccessManager;
+ delete s_bookmarksManager;
+}
+
+#if defined(Q_WS_MAC)
+void BrowserApplication::lastWindowClosed()
+{
+ clean();
+ BrowserMainWindow *mw = new BrowserMainWindow;
+ mw->slotHome();
+ m_mainWindows.prepend(mw);
+}
+#endif
+
+BrowserApplication *BrowserApplication::instance()
+{
+ return (static_cast<BrowserApplication *>(QCoreApplication::instance()));
+}
+
+#if defined(Q_WS_MAC)
+#include <QtGui/QMessageBox>
+void BrowserApplication::quitBrowser()
+{
+ clean();
+ int tabCount = 0;
+ for (int i = 0; i < m_mainWindows.count(); ++i) {
+ tabCount =+ m_mainWindows.at(i)->tabWidget()->count();
+ }
+
+ if (tabCount > 1) {
+ int ret = QMessageBox::warning(mainWindow(), QString(),
+ tr("There are %1 windows and %2 tabs open\n"
+ "Do you want to quit anyway?").arg(m_mainWindows.count()).arg(tabCount),
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::No);
+ if (ret == QMessageBox::No)
+ return;
+ }
+
+ exit(0);
+}
+#endif
+
+/*!
+ Any actions that can be delayed until the window is visible
+ */
+void BrowserApplication::postLaunch()
+{
+ QString directory = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
+ if (directory.isEmpty())
+ directory = QDir::homePath() + QLatin1String("/.") + QCoreApplication::applicationName();
+ QWebSettings::setIconDatabasePath(directory);
+
+ setWindowIcon(QIcon(QLatin1String(":browser.svg")));
+
+ loadSettings();
+
+ // newMainWindow() needs to be called in main() for this to happen
+ if (m_mainWindows.count() > 0) {
+ QStringList args = QCoreApplication::arguments();
+ if (args.count() > 1)
+ mainWindow()->loadPage(args.last());
+ else
+ mainWindow()->slotHome();
+ }
+ BrowserApplication::historyManager();
+}
+
+void BrowserApplication::loadSettings()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("websettings"));
+
+ QWebSettings *defaultSettings = QWebSettings::globalSettings();
+ QString standardFontFamily = defaultSettings->fontFamily(QWebSettings::StandardFont);
+ int standardFontSize = defaultSettings->fontSize(QWebSettings::DefaultFontSize);
+ QFont standardFont = QFont(standardFontFamily, standardFontSize);
+ standardFont = qVariantValue<QFont>(settings.value(QLatin1String("standardFont"), standardFont));
+ defaultSettings->setFontFamily(QWebSettings::StandardFont, standardFont.family());
+ defaultSettings->setFontSize(QWebSettings::DefaultFontSize, standardFont.pointSize());
+
+ QString fixedFontFamily = defaultSettings->fontFamily(QWebSettings::FixedFont);
+ int fixedFontSize = defaultSettings->fontSize(QWebSettings::DefaultFixedFontSize);
+ QFont fixedFont = QFont(fixedFontFamily, fixedFontSize);
+ fixedFont = qVariantValue<QFont>(settings.value(QLatin1String("fixedFont"), fixedFont));
+ defaultSettings->setFontFamily(QWebSettings::FixedFont, fixedFont.family());
+ defaultSettings->setFontSize(QWebSettings::DefaultFixedFontSize, fixedFont.pointSize());
+
+ defaultSettings->setAttribute(QWebSettings::JavascriptEnabled, settings.value(QLatin1String("enableJavascript"), true).toBool());
+ defaultSettings->setAttribute(QWebSettings::PluginsEnabled, settings.value(QLatin1String("enablePlugins"), true).toBool());
+
+ QUrl url = settings.value(QLatin1String("userStyleSheet")).toUrl();
+ defaultSettings->setUserStyleSheetUrl(url);
+
+ settings.endGroup();
+}
+
+QList<BrowserMainWindow*> BrowserApplication::mainWindows()
+{
+ clean();
+ QList<BrowserMainWindow*> list;
+ for (int i = 0; i < m_mainWindows.count(); ++i)
+ list.append(m_mainWindows.at(i));
+ return list;
+}
+
+void BrowserApplication::clean()
+{
+ // cleanup any deleted main windows first
+ for (int i = m_mainWindows.count() - 1; i >= 0; --i)
+ if (m_mainWindows.at(i).isNull())
+ m_mainWindows.removeAt(i);
+}
+
+void BrowserApplication::saveSession()
+{
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled))
+ return;
+
+ clean();
+
+ QSettings settings;
+ settings.beginGroup(QLatin1String("sessions"));
+
+ QByteArray data;
+ QBuffer buffer(&data);
+ QDataStream stream(&buffer);
+ buffer.open(QIODevice::ReadWrite);
+
+ stream << m_mainWindows.count();
+ for (int i = 0; i < m_mainWindows.count(); ++i)
+ stream << m_mainWindows.at(i)->saveState();
+ settings.setValue(QLatin1String("lastSession"), data);
+ settings.endGroup();
+}
+
+bool BrowserApplication::canRestoreSession() const
+{
+ return !m_lastSession.isEmpty();
+}
+
+void BrowserApplication::restoreLastSession()
+{
+ QList<QByteArray> windows;
+ QBuffer buffer(&m_lastSession);
+ QDataStream stream(&buffer);
+ buffer.open(QIODevice::ReadOnly);
+ int windowCount;
+ stream >> windowCount;
+ for (int i = 0; i < windowCount; ++i) {
+ QByteArray windowState;
+ stream >> windowState;
+ windows.append(windowState);
+ }
+ for (int i = 0; i < windows.count(); ++i) {
+ BrowserMainWindow *newWindow = 0;
+ if (m_mainWindows.count() == 1
+ && mainWindow()->tabWidget()->count() == 1
+ && mainWindow()->currentTab()->url() == QUrl()) {
+ newWindow = mainWindow();
+ } else {
+ newWindow = newMainWindow();
+ }
+ newWindow->restoreState(windows.at(i));
+ }
+}
+
+bool BrowserApplication::isTheOnlyBrowser() const
+{
+ return (m_localServer != 0);
+}
+
+void BrowserApplication::installTranslator(const QString &name)
+{
+ QTranslator *translator = new QTranslator(this);
+ translator->load(name, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
+ QApplication::installTranslator(translator);
+}
+
+#if defined(Q_WS_MAC)
+bool BrowserApplication::event(QEvent* event)
+{
+ switch (event->type()) {
+ case QEvent::ApplicationActivate: {
+ clean();
+ if (!m_mainWindows.isEmpty()) {
+ BrowserMainWindow *mw = mainWindow();
+ if (mw && !mw->isMinimized()) {
+ mainWindow()->show();
+ }
+ return true;
+ }
+ }
+ case QEvent::FileOpen:
+ if (!m_mainWindows.isEmpty()) {
+ mainWindow()->loadPage(static_cast<QFileOpenEvent *>(event)->file());
+ return true;
+ }
+ default:
+ break;
+ }
+ return QApplication::event(event);
+}
+#endif
+
+void BrowserApplication::openUrl(const QUrl &url)
+{
+ mainWindow()->loadPage(url.toString());
+}
+
+BrowserMainWindow *BrowserApplication::newMainWindow()
+{
+ BrowserMainWindow *browser = new BrowserMainWindow();
+ m_mainWindows.prepend(browser);
+ browser->show();
+ return browser;
+}
+
+BrowserMainWindow *BrowserApplication::mainWindow()
+{
+ clean();
+ if (m_mainWindows.isEmpty())
+ newMainWindow();
+ return m_mainWindows[0];
+}
+
+void BrowserApplication::newLocalSocketConnection()
+{
+ QLocalSocket *socket = m_localServer->nextPendingConnection();
+ if (!socket)
+ return;
+ socket->waitForReadyRead(1000);
+ QTextStream stream(socket);
+ QString url;
+ stream >> url;
+ if (!url.isEmpty()) {
+ QSettings settings;
+ settings.beginGroup(QLatin1String("general"));
+ int openLinksIn = settings.value(QLatin1String("openLinksIn"), 0).toInt();
+ settings.endGroup();
+ if (openLinksIn == 1)
+ newMainWindow();
+ else
+ mainWindow()->tabWidget()->newTab();
+ openUrl(url);
+ }
+ delete socket;
+ mainWindow()->raise();
+ mainWindow()->activateWindow();
+}
+
+CookieJar *BrowserApplication::cookieJar()
+{
+ return (CookieJar*)networkAccessManager()->cookieJar();
+}
+
+DownloadManager *BrowserApplication::downloadManager()
+{
+ if (!s_downloadManager) {
+ s_downloadManager = new DownloadManager();
+ }
+ return s_downloadManager;
+}
+
+NetworkAccessManager *BrowserApplication::networkAccessManager()
+{
+ if (!s_networkAccessManager) {
+ s_networkAccessManager = new NetworkAccessManager();
+ s_networkAccessManager->setCookieJar(new CookieJar);
+ }
+ return s_networkAccessManager;
+}
+
+HistoryManager *BrowserApplication::historyManager()
+{
+ if (!s_historyManager) {
+ s_historyManager = new HistoryManager();
+ QWebHistoryInterface::setDefaultInterface(s_historyManager);
+ }
+ return s_historyManager;
+}
+
+BookmarksManager *BrowserApplication::bookmarksManager()
+{
+ if (!s_bookmarksManager) {
+ s_bookmarksManager = new BookmarksManager;
+ }
+ return s_bookmarksManager;
+}
+
+QIcon BrowserApplication::icon(const QUrl &url) const
+{
+ QIcon icon = QWebSettings::iconForUrl(url);
+ if (!icon.isNull())
+ return icon.pixmap(16, 16);
+ if (m_defaultIcon.isNull())
+ m_defaultIcon = QIcon(QLatin1String(":defaulticon.png"));
+ return m_defaultIcon.pixmap(16, 16);
+}
+
diff --git a/demos/browser/browserapplication.h b/demos/browser/browserapplication.h
new file mode 100644
index 0000000..6887dfd
--- /dev/null
+++ b/demos/browser/browserapplication.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BROWSERAPPLICATION_H
+#define BROWSERAPPLICATION_H
+
+#include <QtGui/QApplication>
+
+#include <QtCore/QUrl>
+#include <QtCore/QPointer>
+
+#include <QtGui/QIcon>
+
+QT_BEGIN_NAMESPACE
+class QLocalServer;
+QT_END_NAMESPACE
+
+class BookmarksManager;
+class BrowserMainWindow;
+class CookieJar;
+class DownloadManager;
+class HistoryManager;
+class NetworkAccessManager;
+class BrowserApplication : public QApplication
+{
+ Q_OBJECT
+
+public:
+ BrowserApplication(int &argc, char **argv);
+ ~BrowserApplication();
+ static BrowserApplication *instance();
+ void loadSettings();
+
+ bool isTheOnlyBrowser() const;
+ BrowserMainWindow *mainWindow();
+ QList<BrowserMainWindow*> mainWindows();
+ QIcon icon(const QUrl &url) const;
+
+ void saveSession();
+ bool canRestoreSession() const;
+
+ static HistoryManager *historyManager();
+ static CookieJar *cookieJar();
+ static DownloadManager *downloadManager();
+ static NetworkAccessManager *networkAccessManager();
+ static BookmarksManager *bookmarksManager();
+
+#if defined(Q_WS_MAC)
+ bool event(QEvent *event);
+#endif
+
+public slots:
+ BrowserMainWindow *newMainWindow();
+ void restoreLastSession();
+#if defined(Q_WS_MAC)
+ void lastWindowClosed();
+ void quitBrowser();
+#endif
+
+private slots:
+ void postLaunch();
+ void openUrl(const QUrl &url);
+ void newLocalSocketConnection();
+
+private:
+ void clean();
+ void installTranslator(const QString &name);
+
+ static HistoryManager *s_historyManager;
+ static DownloadManager *s_downloadManager;
+ static NetworkAccessManager *s_networkAccessManager;
+ static BookmarksManager *s_bookmarksManager;
+
+ QList<QPointer<BrowserMainWindow> > m_mainWindows;
+ QLocalServer *m_localServer;
+ QByteArray m_lastSession;
+ mutable QIcon m_defaultIcon;
+};
+
+#endif // BROWSERAPPLICATION_H
+
diff --git a/demos/browser/browsermainwindow.cpp b/demos/browser/browsermainwindow.cpp
new file mode 100644
index 0000000..f1dcaef
--- /dev/null
+++ b/demos/browser/browsermainwindow.cpp
@@ -0,0 +1,991 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "browsermainwindow.h"
+
+#include "autosaver.h"
+#include "bookmarks.h"
+#include "browserapplication.h"
+#include "chasewidget.h"
+#include "downloadmanager.h"
+#include "history.h"
+#include "settings.h"
+#include "tabwidget.h"
+#include "toolbarsearch.h"
+#include "ui_passworddialog.h"
+#include "webview.h"
+
+#include <QtCore/QSettings>
+
+#include <QtGui/QDesktopWidget>
+#include <QtGui/QFileDialog>
+#include <QtGui/QPlainTextEdit>
+#include <QtGui/QPrintDialog>
+#include <QtGui/QPrintPreviewDialog>
+#include <QtGui/QPrinter>
+#include <QtGui/QMenuBar>
+#include <QtGui/QMessageBox>
+#include <QtGui/QStatusBar>
+#include <QtGui/QToolBar>
+#include <QtGui/QInputDialog>
+
+#include <QtWebKit/QWebFrame>
+#include <QtWebKit/QWebHistory>
+
+#include <QtCore/QDebug>
+
+BrowserMainWindow::BrowserMainWindow(QWidget *parent, Qt::WindowFlags flags)
+ : QMainWindow(parent, flags)
+ , m_tabWidget(new TabWidget(this))
+ , m_autoSaver(new AutoSaver(this))
+ , m_historyBack(0)
+ , m_historyForward(0)
+ , m_stop(0)
+ , m_reload(0)
+{
+ setAttribute(Qt::WA_DeleteOnClose, true);
+ statusBar()->setSizeGripEnabled(true);
+ setupMenu();
+ setupToolBar();
+
+ QWidget *centralWidget = new QWidget(this);
+ BookmarksModel *boomarksModel = BrowserApplication::bookmarksManager()->bookmarksModel();
+ m_bookmarksToolbar = new BookmarksToolBar(boomarksModel, this);
+ connect(m_bookmarksToolbar, SIGNAL(openUrl(const QUrl&)),
+ m_tabWidget, SLOT(loadUrlInCurrentTab(const QUrl&)));
+ connect(m_bookmarksToolbar->toggleViewAction(), SIGNAL(toggled(bool)),
+ this, SLOT(updateBookmarksToolbarActionText(bool)));
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setSpacing(0);
+ layout->setMargin(0);
+#if defined(Q_WS_MAC)
+ layout->addWidget(m_bookmarksToolbar);
+ layout->addWidget(new QWidget); // <- OS X tab widget style bug
+#else
+ addToolBarBreak();
+ addToolBar(m_bookmarksToolbar);
+#endif
+ layout->addWidget(m_tabWidget);
+ centralWidget->setLayout(layout);
+ setCentralWidget(centralWidget);
+
+ connect(m_tabWidget, SIGNAL(loadPage(const QString &)),
+ this, SLOT(loadPage(const QString &)));
+ connect(m_tabWidget, SIGNAL(setCurrentTitle(const QString &)),
+ this, SLOT(slotUpdateWindowTitle(const QString &)));
+ connect(m_tabWidget, SIGNAL(showStatusBarMessage(const QString&)),
+ statusBar(), SLOT(showMessage(const QString&)));
+ connect(m_tabWidget, SIGNAL(linkHovered(const QString&)),
+ statusBar(), SLOT(showMessage(const QString&)));
+ connect(m_tabWidget, SIGNAL(loadProgress(int)),
+ this, SLOT(slotLoadProgress(int)));
+ connect(m_tabWidget, SIGNAL(tabsChanged()),
+ m_autoSaver, SLOT(changeOccurred()));
+ connect(m_tabWidget, SIGNAL(geometryChangeRequested(const QRect &)),
+ this, SLOT(geometryChangeRequested(const QRect &)));
+ connect(m_tabWidget, SIGNAL(printRequested(QWebFrame *)),
+ this, SLOT(printRequested(QWebFrame *)));
+ connect(m_tabWidget, SIGNAL(menuBarVisibilityChangeRequested(bool)),
+ menuBar(), SLOT(setVisible(bool)));
+ connect(m_tabWidget, SIGNAL(statusBarVisibilityChangeRequested(bool)),
+ statusBar(), SLOT(setVisible(bool)));
+ connect(m_tabWidget, SIGNAL(toolBarVisibilityChangeRequested(bool)),
+ m_navigationBar, SLOT(setVisible(bool)));
+ connect(m_tabWidget, SIGNAL(toolBarVisibilityChangeRequested(bool)),
+ m_bookmarksToolbar, SLOT(setVisible(bool)));
+#if defined(Q_WS_MAC)
+ connect(m_tabWidget, SIGNAL(lastTabClosed()),
+ this, SLOT(close()));
+#else
+ connect(m_tabWidget, SIGNAL(lastTabClosed()),
+ m_tabWidget, SLOT(newTab()));
+#endif
+
+ slotUpdateWindowTitle();
+ loadDefaultState();
+ m_tabWidget->newTab();
+
+ int size = m_tabWidget->lineEditStack()->sizeHint().height();
+ m_navigationBar->setIconSize(QSize(size, size));
+
+}
+
+BrowserMainWindow::~BrowserMainWindow()
+{
+ m_autoSaver->changeOccurred();
+ m_autoSaver->saveIfNeccessary();
+}
+
+void BrowserMainWindow::loadDefaultState()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("BrowserMainWindow"));
+ QByteArray data = settings.value(QLatin1String("defaultState")).toByteArray();
+ restoreState(data);
+ settings.endGroup();
+}
+
+QSize BrowserMainWindow::sizeHint() const
+{
+ QRect desktopRect = QApplication::desktop()->screenGeometry();
+ QSize size = desktopRect.size() * qreal(0.9);
+ return size;
+}
+
+void BrowserMainWindow::save()
+{
+ BrowserApplication::instance()->saveSession();
+
+ QSettings settings;
+ settings.beginGroup(QLatin1String("BrowserMainWindow"));
+ QByteArray data = saveState(false);
+ settings.setValue(QLatin1String("defaultState"), data);
+ settings.endGroup();
+}
+
+static const qint32 BrowserMainWindowMagic = 0xba;
+
+QByteArray BrowserMainWindow::saveState(bool withTabs) const
+{
+ int version = 2;
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+
+ stream << qint32(BrowserMainWindowMagic);
+ stream << qint32(version);
+
+ stream << size();
+ stream << !m_navigationBar->isHidden();
+ stream << !m_bookmarksToolbar->isHidden();
+ stream << !statusBar()->isHidden();
+ if (withTabs)
+ stream << tabWidget()->saveState();
+ else
+ stream << QByteArray();
+ return data;
+}
+
+bool BrowserMainWindow::restoreState(const QByteArray &state)
+{
+ int version = 2;
+ QByteArray sd = state;
+ QDataStream stream(&sd, QIODevice::ReadOnly);
+ if (stream.atEnd())
+ return false;
+
+ qint32 marker;
+ qint32 v;
+ stream >> marker;
+ stream >> v;
+ if (marker != BrowserMainWindowMagic || v != version)
+ return false;
+
+ QSize size;
+ bool showToolbar;
+ bool showBookmarksBar;
+ bool showStatusbar;
+ QByteArray tabState;
+
+ stream >> size;
+ stream >> showToolbar;
+ stream >> showBookmarksBar;
+ stream >> showStatusbar;
+ stream >> tabState;
+
+ resize(size);
+
+ m_navigationBar->setVisible(showToolbar);
+ updateToolbarActionText(showToolbar);
+
+ m_bookmarksToolbar->setVisible(showBookmarksBar);
+ updateBookmarksToolbarActionText(showBookmarksBar);
+
+ statusBar()->setVisible(showStatusbar);
+ updateStatusbarActionText(showStatusbar);
+
+ if (!tabWidget()->restoreState(tabState))
+ return false;
+
+ return true;
+}
+
+void BrowserMainWindow::setupMenu()
+{
+ new QShortcut(QKeySequence(Qt::Key_F6), this, SLOT(slotSwapFocus()));
+
+ // File
+ QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
+
+ fileMenu->addAction(tr("&New Window"), this, SLOT(slotFileNew()), QKeySequence::New);
+ fileMenu->addAction(m_tabWidget->newTabAction());
+ fileMenu->addAction(tr("&Open File..."), this, SLOT(slotFileOpen()), QKeySequence::Open);
+ fileMenu->addAction(tr("Open &Location..."), this,
+ SLOT(slotSelectLineEdit()), QKeySequence(Qt::ControlModifier + Qt::Key_L));
+ fileMenu->addSeparator();
+ fileMenu->addAction(m_tabWidget->closeTabAction());
+ fileMenu->addSeparator();
+ fileMenu->addAction(tr("&Save As..."), this,
+ SLOT(slotFileSaveAs()), QKeySequence(QKeySequence::Save));
+ fileMenu->addSeparator();
+ BookmarksManager *bookmarksManager = BrowserApplication::bookmarksManager();
+ fileMenu->addAction(tr("&Import Bookmarks..."), bookmarksManager, SLOT(importBookmarks()));
+ fileMenu->addAction(tr("&Export Bookmarks..."), bookmarksManager, SLOT(exportBookmarks()));
+ fileMenu->addSeparator();
+ fileMenu->addAction(tr("P&rint Preview..."), this, SLOT(slotFilePrintPreview()));
+ fileMenu->addAction(tr("&Print..."), this, SLOT(slotFilePrint()), QKeySequence::Print);
+ fileMenu->addSeparator();
+ QAction *action = fileMenu->addAction(tr("Private &Browsing..."), this, SLOT(slotPrivateBrowsing()));
+ action->setCheckable(true);
+ fileMenu->addSeparator();
+
+#if defined(Q_WS_MAC)
+ fileMenu->addAction(tr("&Quit"), BrowserApplication::instance(), SLOT(quitBrowser()), QKeySequence(Qt::CTRL | Qt::Key_Q));
+#else
+ fileMenu->addAction(tr("&Quit"), this, SLOT(close()), QKeySequence(Qt::CTRL | Qt::Key_Q));
+#endif
+
+ // Edit
+ QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
+ QAction *m_undo = editMenu->addAction(tr("&Undo"));
+ m_undo->setShortcuts(QKeySequence::Undo);
+ m_tabWidget->addWebAction(m_undo, QWebPage::Undo);
+ QAction *m_redo = editMenu->addAction(tr("&Redo"));
+ m_redo->setShortcuts(QKeySequence::Redo);
+ m_tabWidget->addWebAction(m_redo, QWebPage::Redo);
+ editMenu->addSeparator();
+ QAction *m_cut = editMenu->addAction(tr("Cu&t"));
+ m_cut->setShortcuts(QKeySequence::Cut);
+ m_tabWidget->addWebAction(m_cut, QWebPage::Cut);
+ QAction *m_copy = editMenu->addAction(tr("&Copy"));
+ m_copy->setShortcuts(QKeySequence::Copy);
+ m_tabWidget->addWebAction(m_copy, QWebPage::Copy);
+ QAction *m_paste = editMenu->addAction(tr("&Paste"));
+ m_paste->setShortcuts(QKeySequence::Paste);
+ m_tabWidget->addWebAction(m_paste, QWebPage::Paste);
+ editMenu->addSeparator();
+
+ QAction *m_find = editMenu->addAction(tr("&Find"));
+ m_find->setShortcuts(QKeySequence::Find);
+ connect(m_find, SIGNAL(triggered()), this, SLOT(slotEditFind()));
+ new QShortcut(QKeySequence(Qt::Key_Slash), this, SLOT(slotEditFind()));
+
+ QAction *m_findNext = editMenu->addAction(tr("&Find Next"));
+ m_findNext->setShortcuts(QKeySequence::FindNext);
+ connect(m_findNext, SIGNAL(triggered()), this, SLOT(slotEditFindNext()));
+
+ QAction *m_findPrevious = editMenu->addAction(tr("&Find Previous"));
+ m_findPrevious->setShortcuts(QKeySequence::FindPrevious);
+ connect(m_findPrevious, SIGNAL(triggered()), this, SLOT(slotEditFindPrevious()));
+
+ editMenu->addSeparator();
+ editMenu->addAction(tr("&Preferences"), this, SLOT(slotPreferences()), tr("Ctrl+,"));
+
+ // View
+ QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
+
+ m_viewBookmarkBar = new QAction(this);
+ updateBookmarksToolbarActionText(true);
+ m_viewBookmarkBar->setShortcut(tr("Shift+Ctrl+B"));
+ connect(m_viewBookmarkBar, SIGNAL(triggered()), this, SLOT(slotViewBookmarksBar()));
+ viewMenu->addAction(m_viewBookmarkBar);
+
+ m_viewToolbar = new QAction(this);
+ updateToolbarActionText(true);
+ m_viewToolbar->setShortcut(tr("Ctrl+|"));
+ connect(m_viewToolbar, SIGNAL(triggered()), this, SLOT(slotViewToolbar()));
+ viewMenu->addAction(m_viewToolbar);
+
+ m_viewStatusbar = new QAction(this);
+ updateStatusbarActionText(true);
+ m_viewStatusbar->setShortcut(tr("Ctrl+/"));
+ connect(m_viewStatusbar, SIGNAL(triggered()), this, SLOT(slotViewStatusbar()));
+ viewMenu->addAction(m_viewStatusbar);
+
+ viewMenu->addSeparator();
+
+ m_stop = viewMenu->addAction(tr("&Stop"));
+ QList<QKeySequence> shortcuts;
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Period));
+ shortcuts.append(Qt::Key_Escape);
+ m_stop->setShortcuts(shortcuts);
+ m_tabWidget->addWebAction(m_stop, QWebPage::Stop);
+
+ m_reload = viewMenu->addAction(tr("Reload Page"));
+ m_reload->setShortcuts(QKeySequence::Refresh);
+ m_tabWidget->addWebAction(m_reload, QWebPage::Reload);
+
+ viewMenu->addAction(tr("Zoom &In"), this, SLOT(slotViewZoomIn()), QKeySequence(Qt::CTRL | Qt::Key_Plus));
+ viewMenu->addAction(tr("Zoom &Out"), this, SLOT(slotViewZoomOut()), QKeySequence(Qt::CTRL | Qt::Key_Minus));
+ viewMenu->addAction(tr("Reset &Zoom"), this, SLOT(slotViewResetZoom()), QKeySequence(Qt::CTRL | Qt::Key_0));
+ QAction *zoomTextOnlyAction = viewMenu->addAction(tr("Zoom &Text Only"));
+ connect(zoomTextOnlyAction, SIGNAL(toggled(bool)), this, SLOT(slotViewZoomTextOnly(bool)));
+ zoomTextOnlyAction->setCheckable(true);
+ zoomTextOnlyAction->setChecked(false);
+
+ viewMenu->addSeparator();
+ viewMenu->addAction(tr("Page S&ource"), this, SLOT(slotViewPageSource()), tr("Ctrl+Alt+U"));
+ QAction *a = viewMenu->addAction(tr("&Full Screen"), this, SLOT(slotViewFullScreen(bool)), Qt::Key_F11);
+ a->setCheckable(true);
+
+ // History
+ HistoryMenu *historyMenu = new HistoryMenu(this);
+ connect(historyMenu, SIGNAL(openUrl(const QUrl&)),
+ m_tabWidget, SLOT(loadUrlInCurrentTab(const QUrl&)));
+ connect(historyMenu, SIGNAL(hovered(const QString&)), this,
+ SLOT(slotUpdateStatusbar(const QString&)));
+ historyMenu->setTitle(tr("Hi&story"));
+ menuBar()->addMenu(historyMenu);
+ QList<QAction*> historyActions;
+
+ m_historyBack = new QAction(tr("Back"), this);
+ m_tabWidget->addWebAction(m_historyBack, QWebPage::Back);
+ m_historyBack->setShortcuts(QKeySequence::Back);
+ m_historyBack->setIconVisibleInMenu(false);
+
+ m_historyForward = new QAction(tr("Forward"), this);
+ m_tabWidget->addWebAction(m_historyForward, QWebPage::Forward);
+ m_historyForward->setShortcuts(QKeySequence::Forward);
+ m_historyForward->setIconVisibleInMenu(false);
+
+ QAction *m_historyHome = new QAction(tr("Home"), this);
+ connect(m_historyHome, SIGNAL(triggered()), this, SLOT(slotHome()));
+ m_historyHome->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_H));
+
+ m_restoreLastSession = new QAction(tr("Restore Last Session"), this);
+ connect(m_restoreLastSession, SIGNAL(triggered()), BrowserApplication::instance(), SLOT(restoreLastSession()));
+ m_restoreLastSession->setEnabled(BrowserApplication::instance()->canRestoreSession());
+
+ historyActions.append(m_historyBack);
+ historyActions.append(m_historyForward);
+ historyActions.append(m_historyHome);
+ historyActions.append(m_tabWidget->recentlyClosedTabsAction());
+ historyActions.append(m_restoreLastSession);
+ historyMenu->setInitialActions(historyActions);
+
+ // Bookmarks
+ BookmarksMenu *bookmarksMenu = new BookmarksMenu(this);
+ connect(bookmarksMenu, SIGNAL(openUrl(const QUrl&)),
+ m_tabWidget, SLOT(loadUrlInCurrentTab(const QUrl&)));
+ connect(bookmarksMenu, SIGNAL(hovered(const QString&)),
+ this, SLOT(slotUpdateStatusbar(const QString&)));
+ bookmarksMenu->setTitle(tr("&Bookmarks"));
+ menuBar()->addMenu(bookmarksMenu);
+
+ QList<QAction*> bookmarksActions;
+
+ QAction *showAllBookmarksAction = new QAction(tr("Show All Bookmarks"), this);
+ connect(showAllBookmarksAction, SIGNAL(triggered()), this, SLOT(slotShowBookmarksDialog()));
+ m_addBookmark = new QAction(QIcon(QLatin1String(":addbookmark.png")), tr("Add Bookmark..."), this);
+ m_addBookmark->setIconVisibleInMenu(false);
+
+ connect(m_addBookmark, SIGNAL(triggered()), this, SLOT(slotAddBookmark()));
+ m_addBookmark->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_D));
+
+ bookmarksActions.append(showAllBookmarksAction);
+ bookmarksActions.append(m_addBookmark);
+ bookmarksMenu->setInitialActions(bookmarksActions);
+
+ // Window
+ m_windowMenu = menuBar()->addMenu(tr("&Window"));
+ connect(m_windowMenu, SIGNAL(aboutToShow()),
+ this, SLOT(slotAboutToShowWindowMenu()));
+ slotAboutToShowWindowMenu();
+
+ QMenu *toolsMenu = menuBar()->addMenu(tr("&Tools"));
+ toolsMenu->addAction(tr("Web &Search"), this, SLOT(slotWebSearch()), QKeySequence(tr("Ctrl+K", "Web Search")));
+#ifndef Q_CC_MINGW
+ a = toolsMenu->addAction(tr("Enable Web &Inspector"), this, SLOT(slotToggleInspector(bool)));
+ a->setCheckable(true);
+#endif
+
+ QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
+ helpMenu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt()));
+ helpMenu->addAction(tr("About &Demo Browser"), this, SLOT(slotAboutApplication()));
+}
+
+void BrowserMainWindow::setupToolBar()
+{
+ setUnifiedTitleAndToolBarOnMac(true);
+ m_navigationBar = addToolBar(tr("Navigation"));
+ connect(m_navigationBar->toggleViewAction(), SIGNAL(toggled(bool)),
+ this, SLOT(updateToolbarActionText(bool)));
+
+ m_historyBack->setIcon(style()->standardIcon(QStyle::SP_ArrowBack, 0, this));
+ m_historyBackMenu = new QMenu(this);
+ m_historyBack->setMenu(m_historyBackMenu);
+ connect(m_historyBackMenu, SIGNAL(aboutToShow()),
+ this, SLOT(slotAboutToShowBackMenu()));
+ connect(m_historyBackMenu, SIGNAL(triggered(QAction *)),
+ this, SLOT(slotOpenActionUrl(QAction *)));
+ m_navigationBar->addAction(m_historyBack);
+
+ m_historyForward->setIcon(style()->standardIcon(QStyle::SP_ArrowForward, 0, this));
+ m_historyForwardMenu = new QMenu(this);
+ connect(m_historyForwardMenu, SIGNAL(aboutToShow()),
+ this, SLOT(slotAboutToShowForwardMenu()));
+ connect(m_historyForwardMenu, SIGNAL(triggered(QAction *)),
+ this, SLOT(slotOpenActionUrl(QAction *)));
+ m_historyForward->setMenu(m_historyForwardMenu);
+ m_navigationBar->addAction(m_historyForward);
+
+ m_stopReload = new QAction(this);
+ m_reloadIcon = style()->standardIcon(QStyle::SP_BrowserReload);
+ m_stopReload->setIcon(m_reloadIcon);
+
+ m_navigationBar->addAction(m_stopReload);
+
+ m_navigationBar->addWidget(m_tabWidget->lineEditStack());
+
+ m_toolbarSearch = new ToolbarSearch(m_navigationBar);
+ m_navigationBar->addWidget(m_toolbarSearch);
+ connect(m_toolbarSearch, SIGNAL(search(const QUrl&)), SLOT(loadUrl(const QUrl&)));
+
+ m_chaseWidget = new ChaseWidget(this);
+ m_navigationBar->addWidget(m_chaseWidget);
+}
+
+void BrowserMainWindow::slotShowBookmarksDialog()
+{
+ BookmarksDialog *dialog = new BookmarksDialog(this);
+ connect(dialog, SIGNAL(openUrl(const QUrl&)),
+ m_tabWidget, SLOT(loadUrlInCurrentTab(const QUrl&)));
+ dialog->show();
+}
+
+void BrowserMainWindow::slotAddBookmark()
+{
+ WebView *webView = currentTab();
+ QString url = webView->url().toString();
+ QString title = webView->title();
+ AddBookmarkDialog dialog(url, title);
+ dialog.exec();
+}
+
+void BrowserMainWindow::slotViewToolbar()
+{
+ if (m_navigationBar->isVisible()) {
+ updateToolbarActionText(false);
+ m_navigationBar->close();
+ } else {
+ updateToolbarActionText(true);
+ m_navigationBar->show();
+ }
+ m_autoSaver->changeOccurred();
+}
+
+void BrowserMainWindow::slotViewBookmarksBar()
+{
+ if (m_bookmarksToolbar->isVisible()) {
+ updateBookmarksToolbarActionText(false);
+ m_bookmarksToolbar->close();
+ } else {
+ updateBookmarksToolbarActionText(true);
+ m_bookmarksToolbar->show();
+ }
+ m_autoSaver->changeOccurred();
+}
+
+void BrowserMainWindow::updateStatusbarActionText(bool visible)
+{
+ m_viewStatusbar->setText(!visible ? tr("Show Status Bar") : tr("Hide Status Bar"));
+}
+
+void BrowserMainWindow::updateToolbarActionText(bool visible)
+{
+ m_viewToolbar->setText(!visible ? tr("Show Toolbar") : tr("Hide Toolbar"));
+}
+
+void BrowserMainWindow::updateBookmarksToolbarActionText(bool visible)
+{
+ m_viewBookmarkBar->setText(!visible ? tr("Show Bookmarks bar") : tr("Hide Bookmarks bar"));
+}
+
+void BrowserMainWindow::slotViewStatusbar()
+{
+ if (statusBar()->isVisible()) {
+ updateStatusbarActionText(false);
+ statusBar()->close();
+ } else {
+ updateStatusbarActionText(true);
+ statusBar()->show();
+ }
+ m_autoSaver->changeOccurred();
+}
+
+QUrl BrowserMainWindow::guessUrlFromString(const QString &string)
+{
+ QString urlStr = string.trimmed();
+ QRegExp test(QLatin1String("^[a-zA-Z]+\\:.*"));
+
+ // Check if it looks like a qualified URL. Try parsing it and see.
+ bool hasSchema = test.exactMatch(urlStr);
+ if (hasSchema) {
+ QUrl url = QUrl::fromEncoded(urlStr.toUtf8(), QUrl::TolerantMode);
+ if (url.isValid())
+ return url;
+ }
+
+ // Might be a file.
+ if (QFile::exists(urlStr)) {
+ QFileInfo info(urlStr);
+ return QUrl::fromLocalFile(info.absoluteFilePath());
+ }
+
+ // Might be a shorturl - try to detect the schema.
+ if (!hasSchema) {
+ int dotIndex = urlStr.indexOf(QLatin1Char('.'));
+ if (dotIndex != -1) {
+ QString prefix = urlStr.left(dotIndex).toLower();
+ QByteArray schema = (prefix == QLatin1String("ftp")) ? prefix.toLatin1() : "http";
+ QUrl url =
+ QUrl::fromEncoded(schema + "://" + urlStr.toUtf8(), QUrl::TolerantMode);
+ if (url.isValid())
+ return url;
+ }
+ }
+
+ // Fall back to QUrl's own tolerant parser.
+ QUrl url = QUrl::fromEncoded(string.toUtf8(), QUrl::TolerantMode);
+
+ // finally for cases where the user just types in a hostname add http
+ if (url.scheme().isEmpty())
+ url = QUrl::fromEncoded("http://" + string.toUtf8(), QUrl::TolerantMode);
+ return url;
+}
+
+void BrowserMainWindow::loadUrl(const QUrl &url)
+{
+ if (!currentTab() || !url.isValid())
+ return;
+
+ m_tabWidget->currentLineEdit()->setText(QString::fromUtf8(url.toEncoded()));
+ m_tabWidget->loadUrlInCurrentTab(url);
+}
+
+void BrowserMainWindow::slotDownloadManager()
+{
+ BrowserApplication::downloadManager()->show();
+}
+
+void BrowserMainWindow::slotSelectLineEdit()
+{
+ m_tabWidget->currentLineEdit()->selectAll();
+ m_tabWidget->currentLineEdit()->setFocus();
+}
+
+void BrowserMainWindow::slotFileSaveAs()
+{
+ BrowserApplication::downloadManager()->download(currentTab()->url(), true);
+}
+
+void BrowserMainWindow::slotPreferences()
+{
+ SettingsDialog *s = new SettingsDialog(this);
+ s->show();
+}
+
+void BrowserMainWindow::slotUpdateStatusbar(const QString &string)
+{
+ statusBar()->showMessage(string, 2000);
+}
+
+void BrowserMainWindow::slotUpdateWindowTitle(const QString &title)
+{
+ if (title.isEmpty()) {
+ setWindowTitle(tr("Qt Demo Browser"));
+ } else {
+#if defined(Q_WS_MAC)
+ setWindowTitle(title);
+#else
+ setWindowTitle(tr("%1 - Qt Demo Browser", "Page title and Browser name").arg(title));
+#endif
+ }
+}
+
+void BrowserMainWindow::slotAboutApplication()
+{
+ QMessageBox::about(this, tr("About"), tr(
+ "Version %1"
+ "<p>This demo demonstrates Qt's "
+ "webkit facilities in action, providing an example "
+ "browser for you to experiment with.<p>"
+ "<p>QtWebKit is based on the Open Source WebKit Project developed at <a href=\"http://webkit.org/\">http://webkit.org/</a>."
+ ).arg(QCoreApplication::applicationVersion()));
+}
+
+void BrowserMainWindow::slotFileNew()
+{
+ BrowserApplication::instance()->newMainWindow();
+ BrowserMainWindow *mw = BrowserApplication::instance()->mainWindow();
+ mw->slotHome();
+}
+
+void BrowserMainWindow::slotFileOpen()
+{
+ QString file = QFileDialog::getOpenFileName(this, tr("Open Web Resource"), QString(),
+ tr("Web Resources (*.html *.htm *.svg *.png *.gif *.svgz);;All files (*.*)"));
+
+ if (file.isEmpty())
+ return;
+
+ loadPage(file);
+}
+
+void BrowserMainWindow::slotFilePrintPreview()
+{
+#ifndef QT_NO_PRINTER
+ if (!currentTab())
+ return;
+ QPrintPreviewDialog *dialog = new QPrintPreviewDialog(this);
+ connect(dialog, SIGNAL(paintRequested(QPrinter *)),
+ currentTab(), SLOT(print(QPrinter *)));
+ dialog->exec();
+#endif
+}
+
+void BrowserMainWindow::slotFilePrint()
+{
+ if (!currentTab())
+ return;
+ printRequested(currentTab()->page()->mainFrame());
+}
+
+void BrowserMainWindow::printRequested(QWebFrame *frame)
+{
+#ifndef QT_NO_PRINTER
+ QPrinter printer;
+ QPrintDialog *dialog = new QPrintDialog(&printer, this);
+ dialog->setWindowTitle(tr("Print Document"));
+ if (dialog->exec() != QDialog::Accepted)
+ return;
+ frame->print(&printer);
+#endif
+}
+
+void BrowserMainWindow::slotPrivateBrowsing()
+{
+ QWebSettings *settings = QWebSettings::globalSettings();
+ bool pb = settings->testAttribute(QWebSettings::PrivateBrowsingEnabled);
+ if (!pb) {
+ QString title = tr("Are you sure you want to turn on private browsing?");
+ QString text = tr("<b>%1</b><br><br>When private browsing in turned on,"
+ " webpages are not added to the history,"
+ " items are automatically removed from the Downloads window," \
+ " new cookies are not stored, current cookies can't be accessed," \
+ " site icons wont be stored, session wont be saved, " \
+ " and searches are not addded to the pop-up menu in the Google search box." \
+ " Until you close the window, you can still click the Back and Forward buttons" \
+ " to return to the webpages you have opened.").arg(title);
+
+ QMessageBox::StandardButton button = QMessageBox::question(this, QString(), text,
+ QMessageBox::Ok | QMessageBox::Cancel,
+ QMessageBox::Ok);
+ if (button == QMessageBox::Ok) {
+ settings->setAttribute(QWebSettings::PrivateBrowsingEnabled, true);
+ }
+ } else {
+ settings->setAttribute(QWebSettings::PrivateBrowsingEnabled, false);
+
+ QList<BrowserMainWindow*> windows = BrowserApplication::instance()->mainWindows();
+ for (int i = 0; i < windows.count(); ++i) {
+ BrowserMainWindow *window = windows.at(i);
+ window->m_lastSearch = QString::null;
+ window->tabWidget()->clear();
+ }
+ }
+}
+
+void BrowserMainWindow::closeEvent(QCloseEvent *event)
+{
+ if (m_tabWidget->count() > 1) {
+ int ret = QMessageBox::warning(this, QString(),
+ tr("Are you sure you want to close the window?"
+ " There are %1 tab open").arg(m_tabWidget->count()),
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::No);
+ if (ret == QMessageBox::No) {
+ event->ignore();
+ return;
+ }
+ }
+ event->accept();
+ deleteLater();
+}
+
+void BrowserMainWindow::slotEditFind()
+{
+ if (!currentTab())
+ return;
+ bool ok;
+ QString search = QInputDialog::getText(this, tr("Find"),
+ tr("Text:"), QLineEdit::Normal,
+ m_lastSearch, &ok);
+ if (ok && !search.isEmpty()) {
+ m_lastSearch = search;
+ if (!currentTab()->findText(m_lastSearch))
+ slotUpdateStatusbar(tr("\"%1\" not found.").arg(m_lastSearch));
+ }
+}
+
+void BrowserMainWindow::slotEditFindNext()
+{
+ if (!currentTab() && !m_lastSearch.isEmpty())
+ return;
+ currentTab()->findText(m_lastSearch);
+}
+
+void BrowserMainWindow::slotEditFindPrevious()
+{
+ if (!currentTab() && !m_lastSearch.isEmpty())
+ return;
+ currentTab()->findText(m_lastSearch, QWebPage::FindBackward);
+}
+
+void BrowserMainWindow::slotViewZoomIn()
+{
+ if (!currentTab())
+ return;
+ currentTab()->setZoomFactor(currentTab()->zoomFactor() + 0.1);
+}
+
+void BrowserMainWindow::slotViewZoomOut()
+{
+ if (!currentTab())
+ return;
+ currentTab()->setZoomFactor(currentTab()->zoomFactor() - 0.1);
+}
+
+void BrowserMainWindow::slotViewResetZoom()
+{
+ if (!currentTab())
+ return;
+ currentTab()->setZoomFactor(1.0);
+}
+
+void BrowserMainWindow::slotViewZoomTextOnly(bool enable)
+{
+ if (!currentTab())
+ return;
+ currentTab()->page()->settings()->setAttribute(QWebSettings::ZoomTextOnly, enable);
+}
+
+void BrowserMainWindow::slotViewFullScreen(bool makeFullScreen)
+{
+ if (makeFullScreen) {
+ showFullScreen();
+ } else {
+ if (isMinimized())
+ showMinimized();
+ else if (isMaximized())
+ showMaximized();
+ else showNormal();
+ }
+}
+
+void BrowserMainWindow::slotViewPageSource()
+{
+ if (!currentTab())
+ return;
+
+ QString markup = currentTab()->page()->mainFrame()->toHtml();
+ QPlainTextEdit *view = new QPlainTextEdit(markup);
+ view->setWindowTitle(tr("Page Source of %1").arg(currentTab()->title()));
+ view->setMinimumWidth(640);
+ view->setAttribute(Qt::WA_DeleteOnClose);
+ view->show();
+}
+
+void BrowserMainWindow::slotHome()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("MainWindow"));
+ QString home = settings.value(QLatin1String("home"), QLatin1String("http://qtsoftware.com/")).toString();
+ loadPage(home);
+}
+
+void BrowserMainWindow::slotWebSearch()
+{
+ m_toolbarSearch->lineEdit()->selectAll();
+ m_toolbarSearch->lineEdit()->setFocus();
+}
+
+void BrowserMainWindow::slotToggleInspector(bool enable)
+{
+ QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, enable);
+ if (enable) {
+ int result = QMessageBox::question(this, tr("Web Inspector"),
+ tr("The web inspector will only work correctly for pages that were loaded after enabling.\n"
+ "Do you want to reload all pages?"),
+ QMessageBox::Yes | QMessageBox::No);
+ if (result == QMessageBox::Yes) {
+ m_tabWidget->reloadAllTabs();
+ }
+ }
+}
+
+void BrowserMainWindow::slotSwapFocus()
+{
+ if (currentTab()->hasFocus())
+ m_tabWidget->currentLineEdit()->setFocus();
+ else
+ currentTab()->setFocus();
+}
+
+void BrowserMainWindow::loadPage(const QString &page)
+{
+ QUrl url = guessUrlFromString(page);
+ loadUrl(url);
+}
+
+TabWidget *BrowserMainWindow::tabWidget() const
+{
+ return m_tabWidget;
+}
+
+WebView *BrowserMainWindow::currentTab() const
+{
+ return m_tabWidget->currentWebView();
+}
+
+void BrowserMainWindow::slotLoadProgress(int progress)
+{
+ if (progress < 100 && progress > 0) {
+ m_chaseWidget->setAnimated(true);
+ disconnect(m_stopReload, SIGNAL(triggered()), m_reload, SLOT(trigger()));
+ if (m_stopIcon.isNull())
+ m_stopIcon = style()->standardIcon(QStyle::SP_BrowserStop);
+ m_stopReload->setIcon(m_stopIcon);
+ connect(m_stopReload, SIGNAL(triggered()), m_stop, SLOT(trigger()));
+ m_stopReload->setToolTip(tr("Stop loading the current page"));
+ } else {
+ m_chaseWidget->setAnimated(false);
+ disconnect(m_stopReload, SIGNAL(triggered()), m_stop, SLOT(trigger()));
+ m_stopReload->setIcon(m_reloadIcon);
+ connect(m_stopReload, SIGNAL(triggered()), m_reload, SLOT(trigger()));
+ m_stopReload->setToolTip(tr("Reload the current page"));
+ }
+}
+
+void BrowserMainWindow::slotAboutToShowBackMenu()
+{
+ m_historyBackMenu->clear();
+ if (!currentTab())
+ return;
+ QWebHistory *history = currentTab()->history();
+ int historyCount = history->count();
+ for (int i = history->backItems(historyCount).count() - 1; i >= 0; --i) {
+ QWebHistoryItem item = history->backItems(history->count()).at(i);
+ QAction *action = new QAction(this);
+ action->setData(-1*(historyCount-i-1));
+ QIcon icon = BrowserApplication::instance()->icon(item.url());
+ action->setIcon(icon);
+ action->setText(item.title());
+ m_historyBackMenu->addAction(action);
+ }
+}
+
+void BrowserMainWindow::slotAboutToShowForwardMenu()
+{
+ m_historyForwardMenu->clear();
+ if (!currentTab())
+ return;
+ QWebHistory *history = currentTab()->history();
+ int historyCount = history->count();
+ for (int i = 0; i < history->forwardItems(history->count()).count(); ++i) {
+ QWebHistoryItem item = history->forwardItems(historyCount).at(i);
+ QAction *action = new QAction(this);
+ action->setData(historyCount-i);
+ QIcon icon = BrowserApplication::instance()->icon(item.url());
+ action->setIcon(icon);
+ action->setText(item.title());
+ m_historyForwardMenu->addAction(action);
+ }
+}
+
+void BrowserMainWindow::slotAboutToShowWindowMenu()
+{
+ m_windowMenu->clear();
+ m_windowMenu->addAction(m_tabWidget->nextTabAction());
+ m_windowMenu->addAction(m_tabWidget->previousTabAction());
+ m_windowMenu->addSeparator();
+ m_windowMenu->addAction(tr("Downloads"), this, SLOT(slotDownloadManager()), QKeySequence(tr("Alt+Ctrl+L", "Download Manager")));
+
+ m_windowMenu->addSeparator();
+ QList<BrowserMainWindow*> windows = BrowserApplication::instance()->mainWindows();
+ for (int i = 0; i < windows.count(); ++i) {
+ BrowserMainWindow *window = windows.at(i);
+ QAction *action = m_windowMenu->addAction(window->windowTitle(), this, SLOT(slotShowWindow()));
+ action->setData(i);
+ action->setCheckable(true);
+ if (window == this)
+ action->setChecked(true);
+ }
+}
+
+void BrowserMainWindow::slotShowWindow()
+{
+ if (QAction *action = qobject_cast<QAction*>(sender())) {
+ QVariant v = action->data();
+ if (v.canConvert<int>()) {
+ int offset = qvariant_cast<int>(v);
+ QList<BrowserMainWindow*> windows = BrowserApplication::instance()->mainWindows();
+ windows.at(offset)->activateWindow();
+ windows.at(offset)->currentTab()->setFocus();
+ }
+ }
+}
+
+void BrowserMainWindow::slotOpenActionUrl(QAction *action)
+{
+ int offset = action->data().toInt();
+ QWebHistory *history = currentTab()->history();
+ if (offset < 0)
+ history->goToItem(history->backItems(-1*offset).first()); // back
+ else if (offset > 0)
+ history->goToItem(history->forwardItems(history->count() - offset + 1).back()); // forward
+ }
+
+void BrowserMainWindow::geometryChangeRequested(const QRect &geometry)
+{
+ setGeometry(geometry);
+}
+
diff --git a/demos/browser/browsermainwindow.h b/demos/browser/browsermainwindow.h
new file mode 100644
index 0000000..eaf976c
--- /dev/null
+++ b/demos/browser/browsermainwindow.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BROWSERMAINWINDOW_H
+#define BROWSERMAINWINDOW_H
+
+#include <QtGui/QMainWindow>
+#include <QtGui/QIcon>
+#include <QtCore/QUrl>
+
+class AutoSaver;
+class BookmarksToolBar;
+class ChaseWidget;
+class QWebFrame;
+class TabWidget;
+class ToolbarSearch;
+class WebView;
+
+/*!
+ The MainWindow of the Browser Application.
+
+ Handles the tab widget and all the actions
+ */
+class BrowserMainWindow : public QMainWindow {
+ Q_OBJECT
+
+public:
+ BrowserMainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ ~BrowserMainWindow();
+ QSize sizeHint() const;
+
+public:
+ static QUrl guessUrlFromString(const QString &url);
+ TabWidget *tabWidget() const;
+ WebView *currentTab() const;
+ QByteArray saveState(bool withTabs = true) const;
+ bool restoreState(const QByteArray &state);
+
+public slots:
+ void loadPage(const QString &url);
+ void slotHome();
+
+protected:
+ void closeEvent(QCloseEvent *event);
+
+private slots:
+ void save();
+
+ void slotLoadProgress(int);
+ void slotUpdateStatusbar(const QString &string);
+ void slotUpdateWindowTitle(const QString &title = QString());
+
+ void loadUrl(const QUrl &url);
+ void slotPreferences();
+
+ void slotFileNew();
+ void slotFileOpen();
+ void slotFilePrintPreview();
+ void slotFilePrint();
+ void slotPrivateBrowsing();
+ void slotFileSaveAs();
+ void slotEditFind();
+ void slotEditFindNext();
+ void slotEditFindPrevious();
+ void slotShowBookmarksDialog();
+ void slotAddBookmark();
+ void slotViewZoomIn();
+ void slotViewZoomOut();
+ void slotViewResetZoom();
+ void slotViewZoomTextOnly(bool enable);
+ void slotViewToolbar();
+ void slotViewBookmarksBar();
+ void slotViewStatusbar();
+ void slotViewPageSource();
+ void slotViewFullScreen(bool enable);
+
+ void slotWebSearch();
+ void slotToggleInspector(bool enable);
+ void slotAboutApplication();
+ void slotDownloadManager();
+ void slotSelectLineEdit();
+
+ void slotAboutToShowBackMenu();
+ void slotAboutToShowForwardMenu();
+ void slotAboutToShowWindowMenu();
+ void slotOpenActionUrl(QAction *action);
+ void slotShowWindow();
+ void slotSwapFocus();
+
+ void printRequested(QWebFrame *frame);
+ void geometryChangeRequested(const QRect &geometry);
+ void updateToolbarActionText(bool visible);
+ void updateBookmarksToolbarActionText(bool visible);
+
+private:
+ void loadDefaultState();
+ void setupMenu();
+ void setupToolBar();
+ void updateStatusbarActionText(bool visible);
+
+private:
+ QToolBar *m_navigationBar;
+ ToolbarSearch *m_toolbarSearch;
+ BookmarksToolBar *m_bookmarksToolbar;
+ ChaseWidget *m_chaseWidget;
+ TabWidget *m_tabWidget;
+ AutoSaver *m_autoSaver;
+
+ QAction *m_historyBack;
+ QMenu *m_historyBackMenu;
+ QAction *m_historyForward;
+ QMenu *m_historyForwardMenu;
+ QMenu *m_windowMenu;
+
+ QAction *m_stop;
+ QAction *m_reload;
+ QAction *m_stopReload;
+ QAction *m_viewToolbar;
+ QAction *m_viewBookmarkBar;
+ QAction *m_viewStatusbar;
+ QAction *m_restoreLastSession;
+ QAction *m_addBookmark;
+
+ QIcon m_reloadIcon;
+ QIcon m_stopIcon;
+
+ QString m_lastSearch;
+};
+
+#endif // BROWSERMAINWINDOW_H
+
diff --git a/demos/browser/chasewidget.cpp b/demos/browser/chasewidget.cpp
new file mode 100644
index 0000000..7ebe282
--- /dev/null
+++ b/demos/browser/chasewidget.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "chasewidget.h"
+
+#include <QtCore/QPoint>
+
+#include <QtGui/QApplication>
+#include <QtGui/QHideEvent>
+#include <QtGui/QPainter>
+#include <QtGui/QPaintEvent>
+#include <QtGui/QShowEvent>
+
+ChaseWidget::ChaseWidget(QWidget *parent, QPixmap pixmap, bool pixmapEnabled)
+ : QWidget(parent)
+ , m_segment(0)
+ , m_delay(100)
+ , m_step(40)
+ , m_timerId(-1)
+ , m_animated(false)
+ , m_pixmap(pixmap)
+ , m_pixmapEnabled(pixmapEnabled)
+{
+}
+
+void ChaseWidget::setAnimated(bool value)
+{
+ if (m_animated == value)
+ return;
+ m_animated = value;
+ if (m_timerId != -1) {
+ killTimer(m_timerId);
+ m_timerId = -1;
+ }
+ if (m_animated) {
+ m_segment = 0;
+ m_timerId = startTimer(m_delay);
+ }
+ update();
+}
+
+void ChaseWidget::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+ QPainter p(this);
+ if (m_pixmapEnabled && !m_pixmap.isNull()) {
+ p.drawPixmap(0, 0, m_pixmap);
+ return;
+ }
+
+ const int extent = qMin(width() - 8, height() - 8);
+ const int displ = extent / 4;
+ const int ext = extent / 4 - 1;
+
+ p.setRenderHint(QPainter::Antialiasing, true);
+
+ if(m_animated)
+ p.setPen(Qt::gray);
+ else
+ p.setPen(QPen(palette().dark().color()));
+
+ p.translate(width() / 2, height() / 2); // center
+
+ for (int segment = 0; segment < segmentCount(); ++segment) {
+ p.rotate(QApplication::isRightToLeft() ? m_step : -m_step);
+ if(m_animated)
+ p.setBrush(colorForSegment(segment));
+ else
+ p.setBrush(palette().background());
+ p.drawEllipse(QRect(displ, -ext / 2, ext, ext));
+ }
+}
+
+QSize ChaseWidget::sizeHint() const
+{
+ return QSize(32, 32);
+}
+
+void ChaseWidget::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == m_timerId) {
+ ++m_segment;
+ update();
+ }
+ QWidget::timerEvent(event);
+}
+
+QColor ChaseWidget::colorForSegment(int seg) const
+{
+ int index = ((seg + m_segment) % segmentCount());
+ int comp = qMax(0, 255 - (index * (255 / segmentCount())));
+ return QColor(comp, comp, comp, 255);
+}
+
+int ChaseWidget::segmentCount() const
+{
+ return 360 / m_step;
+}
+
+void ChaseWidget::setPixmapEnabled(bool enable)
+{
+ m_pixmapEnabled = enable;
+}
+
diff --git a/demos/browser/chasewidget.h b/demos/browser/chasewidget.h
new file mode 100644
index 0000000..78968ba
--- /dev/null
+++ b/demos/browser/chasewidget.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CHASEWIDGET_H
+#define CHASEWIDGET_H
+
+#include <QtGui/QWidget>
+
+#include <QtCore/QSize>
+#include <QtGui/QColor>
+#include <QtGui/QPixmap>
+
+QT_BEGIN_NAMESPACE
+class QHideEvent;
+class QShowEvent;
+class QPaintEvent;
+class QTimerEvent;
+QT_END_NAMESPACE
+
+class ChaseWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ ChaseWidget(QWidget *parent = 0, QPixmap pixmap = QPixmap(), bool pixmapEnabled = false);
+
+ void setAnimated(bool value);
+ void setPixmapEnabled(bool enable);
+ QSize sizeHint() const;
+
+protected:
+ void paintEvent(QPaintEvent *event);
+ void timerEvent(QTimerEvent *event);
+
+private:
+ int segmentCount() const;
+ QColor colorForSegment(int segment) const;
+
+ int m_segment;
+ int m_delay;
+ int m_step;
+ int m_timerId;
+ bool m_animated;
+ QPixmap m_pixmap;
+ bool m_pixmapEnabled;
+};
+
+#endif
diff --git a/demos/browser/cookiejar.cpp b/demos/browser/cookiejar.cpp
new file mode 100644
index 0000000..9e11c8e
--- /dev/null
+++ b/demos/browser/cookiejar.cpp
@@ -0,0 +1,733 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "cookiejar.h"
+
+#include "autosaver.h"
+
+#include <QtCore/QDateTime>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QMetaEnum>
+#include <QtCore/QSettings>
+#include <QtCore/QUrl>
+
+#include <QtGui/QCompleter>
+#include <QtGui/QDesktopServices>
+#include <QtGui/QFont>
+#include <QtGui/QFontMetrics>
+#include <QtGui/QHeaderView>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QSortFilterProxyModel>
+
+#include <QtWebKit/QWebSettings>
+
+#include <QtCore/QDebug>
+
+static const unsigned int JAR_VERSION = 23;
+
+QT_BEGIN_NAMESPACE
+QDataStream &operator<<(QDataStream &stream, const QList<QNetworkCookie> &list)
+{
+ stream << JAR_VERSION;
+ stream << quint32(list.size());
+ for (int i = 0; i < list.size(); ++i)
+ stream << list.at(i).toRawForm();
+ return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list)
+{
+ list.clear();
+
+ quint32 version;
+ stream >> version;
+
+ if (version != JAR_VERSION)
+ return stream;
+
+ quint32 count;
+ stream >> count;
+ for(quint32 i = 0; i < count; ++i)
+ {
+ QByteArray value;
+ stream >> value;
+ QList<QNetworkCookie> newCookies = QNetworkCookie::parseCookies(value);
+ if (newCookies.count() == 0 && value.length() != 0) {
+ qWarning() << "CookieJar: Unable to parse saved cookie:" << value;
+ }
+ for (int j = 0; j < newCookies.count(); ++j)
+ list.append(newCookies.at(j));
+ if (stream.atEnd())
+ break;
+ }
+ return stream;
+}
+QT_END_NAMESPACE
+
+CookieJar::CookieJar(QObject *parent)
+ : QNetworkCookieJar(parent)
+ , m_loaded(false)
+ , m_saveTimer(new AutoSaver(this))
+ , m_acceptCookies(AcceptOnlyFromSitesNavigatedTo)
+{
+}
+
+CookieJar::~CookieJar()
+{
+ if (m_keepCookies == KeepUntilExit)
+ clear();
+ m_saveTimer->saveIfNeccessary();
+}
+
+void CookieJar::clear()
+{
+ setAllCookies(QList<QNetworkCookie>());
+ m_saveTimer->changeOccurred();
+ emit cookiesChanged();
+}
+
+void CookieJar::load()
+{
+ if (m_loaded)
+ return;
+ // load cookies and exceptions
+ qRegisterMetaTypeStreamOperators<QList<QNetworkCookie> >("QList<QNetworkCookie>");
+ QSettings cookieSettings(QDesktopServices::storageLocation(QDesktopServices::DataLocation) + QLatin1String("/cookies.ini"), QSettings::IniFormat);
+ setAllCookies(qvariant_cast<QList<QNetworkCookie> >(cookieSettings.value(QLatin1String("cookies"))));
+ cookieSettings.beginGroup(QLatin1String("Exceptions"));
+ m_exceptions_block = cookieSettings.value(QLatin1String("block")).toStringList();
+ m_exceptions_allow = cookieSettings.value(QLatin1String("allow")).toStringList();
+ m_exceptions_allowForSession = cookieSettings.value(QLatin1String("allowForSession")).toStringList();
+ qSort(m_exceptions_block.begin(), m_exceptions_block.end());
+ qSort(m_exceptions_allow.begin(), m_exceptions_allow.end());
+ qSort(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end());
+
+ loadSettings();
+}
+
+void CookieJar::loadSettings()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("cookies"));
+ QByteArray value = settings.value(QLatin1String("acceptCookies"),
+ QLatin1String("AcceptOnlyFromSitesNavigatedTo")).toByteArray();
+ QMetaEnum acceptPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("AcceptPolicy"));
+ m_acceptCookies = acceptPolicyEnum.keyToValue(value) == -1 ?
+ AcceptOnlyFromSitesNavigatedTo :
+ static_cast<AcceptPolicy>(acceptPolicyEnum.keyToValue(value));
+
+ value = settings.value(QLatin1String("keepCookiesUntil"), QLatin1String("KeepUntilExpire")).toByteArray();
+ QMetaEnum keepPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("KeepPolicy"));
+ m_keepCookies = keepPolicyEnum.keyToValue(value) == -1 ?
+ KeepUntilExpire :
+ static_cast<KeepPolicy>(keepPolicyEnum.keyToValue(value));
+
+ if (m_keepCookies == KeepUntilExit)
+ setAllCookies(QList<QNetworkCookie>());
+
+ m_loaded = true;
+ emit cookiesChanged();
+}
+
+void CookieJar::save()
+{
+ if (!m_loaded)
+ return;
+ purgeOldCookies();
+ QString directory = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
+ if (directory.isEmpty())
+ directory = QDir::homePath() + QLatin1String("/.") + QCoreApplication::applicationName();
+ if (!QFile::exists(directory)) {
+ QDir dir;
+ dir.mkpath(directory);
+ }
+ QSettings cookieSettings(directory + QLatin1String("/cookies.ini"), QSettings::IniFormat);
+ QList<QNetworkCookie> cookies = allCookies();
+ for (int i = cookies.count() - 1; i >= 0; --i) {
+ if (cookies.at(i).isSessionCookie())
+ cookies.removeAt(i);
+ }
+ cookieSettings.setValue(QLatin1String("cookies"), qVariantFromValue<QList<QNetworkCookie> >(cookies));
+ cookieSettings.beginGroup(QLatin1String("Exceptions"));
+ cookieSettings.setValue(QLatin1String("block"), m_exceptions_block);
+ cookieSettings.setValue(QLatin1String("allow"), m_exceptions_allow);
+ cookieSettings.setValue(QLatin1String("allowForSession"), m_exceptions_allowForSession);
+
+ // save cookie settings
+ QSettings settings;
+ settings.beginGroup(QLatin1String("cookies"));
+ QMetaEnum acceptPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("AcceptPolicy"));
+ settings.setValue(QLatin1String("acceptCookies"), QLatin1String(acceptPolicyEnum.valueToKey(m_acceptCookies)));
+
+ QMetaEnum keepPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("KeepPolicy"));
+ settings.setValue(QLatin1String("keepCookiesUntil"), QLatin1String(keepPolicyEnum.valueToKey(m_keepCookies)));
+}
+
+void CookieJar::purgeOldCookies()
+{
+ QList<QNetworkCookie> cookies = allCookies();
+ if (cookies.isEmpty())
+ return;
+ int oldCount = cookies.count();
+ QDateTime now = QDateTime::currentDateTime();
+ for (int i = cookies.count() - 1; i >= 0; --i) {
+ if (!cookies.at(i).isSessionCookie() && cookies.at(i).expirationDate() < now)
+ cookies.removeAt(i);
+ }
+ if (oldCount == cookies.count())
+ return;
+ setAllCookies(cookies);
+ emit cookiesChanged();
+}
+
+QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const
+{
+ CookieJar *that = const_cast<CookieJar*>(this);
+ if (!m_loaded)
+ that->load();
+
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) {
+ QList<QNetworkCookie> noCookies;
+ return noCookies;
+ }
+
+ return QNetworkCookieJar::cookiesForUrl(url);
+}
+
+bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
+{
+ if (!m_loaded)
+ load();
+
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled))
+ return false;
+
+ QString host = url.host();
+ bool eBlock = qBinaryFind(m_exceptions_block.begin(), m_exceptions_block.end(), host) != m_exceptions_block.end();
+ bool eAllow = qBinaryFind(m_exceptions_allow.begin(), m_exceptions_allow.end(), host) != m_exceptions_allow.end();
+ bool eAllowSession = qBinaryFind(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end(), host) != m_exceptions_allowForSession.end();
+
+ bool addedCookies = false;
+ // pass exceptions
+ bool acceptInitially = (m_acceptCookies != AcceptNever);
+ if ((acceptInitially && !eBlock)
+ || (!acceptInitially && (eAllow || eAllowSession))) {
+ // pass url domain == cookie domain
+ QDateTime soon = QDateTime::currentDateTime();
+ soon = soon.addDays(90);
+ foreach(QNetworkCookie cookie, cookieList) {
+ QList<QNetworkCookie> lst;
+ if (m_keepCookies == KeepUntilTimeLimit
+ && !cookie.isSessionCookie()
+ && cookie.expirationDate() > soon) {
+ cookie.setExpirationDate(soon);
+ }
+ lst += cookie;
+ if (QNetworkCookieJar::setCookiesFromUrl(lst, url)) {
+ addedCookies = true;
+ } else {
+ // finally force it in if wanted
+ if (m_acceptCookies == AcceptAlways) {
+ QList<QNetworkCookie> cookies = allCookies();
+ cookies += cookie;
+ setAllCookies(cookies);
+ addedCookies = true;
+ }
+#if 0
+ else
+ qWarning() << "setCookiesFromUrl failed" << url << cookieList.value(0).toRawForm();
+#endif
+ }
+ }
+ }
+
+ if (addedCookies) {
+ m_saveTimer->changeOccurred();
+ emit cookiesChanged();
+ }
+ return addedCookies;
+}
+
+CookieJar::AcceptPolicy CookieJar::acceptPolicy() const
+{
+ if (!m_loaded)
+ (const_cast<CookieJar*>(this))->load();
+ return m_acceptCookies;
+}
+
+void CookieJar::setAcceptPolicy(AcceptPolicy policy)
+{
+ if (!m_loaded)
+ load();
+ if (policy == m_acceptCookies)
+ return;
+ m_acceptCookies = policy;
+ m_saveTimer->changeOccurred();
+}
+
+CookieJar::KeepPolicy CookieJar::keepPolicy() const
+{
+ if (!m_loaded)
+ (const_cast<CookieJar*>(this))->load();
+ return m_keepCookies;
+}
+
+void CookieJar::setKeepPolicy(KeepPolicy policy)
+{
+ if (!m_loaded)
+ load();
+ if (policy == m_keepCookies)
+ return;
+ m_keepCookies = policy;
+ m_saveTimer->changeOccurred();
+}
+
+QStringList CookieJar::blockedCookies() const
+{
+ if (!m_loaded)
+ (const_cast<CookieJar*>(this))->load();
+ return m_exceptions_block;
+}
+
+QStringList CookieJar::allowedCookies() const
+{
+ if (!m_loaded)
+ (const_cast<CookieJar*>(this))->load();
+ return m_exceptions_allow;
+}
+
+QStringList CookieJar::allowForSessionCookies() const
+{
+ if (!m_loaded)
+ (const_cast<CookieJar*>(this))->load();
+ return m_exceptions_allowForSession;
+}
+
+void CookieJar::setBlockedCookies(const QStringList &list)
+{
+ if (!m_loaded)
+ load();
+ m_exceptions_block = list;
+ qSort(m_exceptions_block.begin(), m_exceptions_block.end());
+ m_saveTimer->changeOccurred();
+}
+
+void CookieJar::setAllowedCookies(const QStringList &list)
+{
+ if (!m_loaded)
+ load();
+ m_exceptions_allow = list;
+ qSort(m_exceptions_allow.begin(), m_exceptions_allow.end());
+ m_saveTimer->changeOccurred();
+}
+
+void CookieJar::setAllowForSessionCookies(const QStringList &list)
+{
+ if (!m_loaded)
+ load();
+ m_exceptions_allowForSession = list;
+ qSort(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end());
+ m_saveTimer->changeOccurred();
+}
+
+CookieModel::CookieModel(CookieJar *cookieJar, QObject *parent)
+ : QAbstractTableModel(parent)
+ , m_cookieJar(cookieJar)
+{
+ connect(m_cookieJar, SIGNAL(cookiesChanged()), this, SLOT(cookiesChanged()));
+ m_cookieJar->load();
+}
+
+QVariant CookieModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role == Qt::SizeHintRole) {
+ QFont font;
+ font.setPointSize(10);
+ QFontMetrics fm(font);
+ int height = fm.height() + fm.height()/3;
+ int width = fm.width(headerData(section, orientation, Qt::DisplayRole).toString());
+ return QSize(width, height);
+ }
+
+ if (orientation == Qt::Horizontal) {
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ switch (section) {
+ case 0:
+ return tr("Website");
+ case 1:
+ return tr("Name");
+ case 2:
+ return tr("Path");
+ case 3:
+ return tr("Secure");
+ case 4:
+ return tr("Expires");
+ case 5:
+ return tr("Contents");
+ default:
+ return QVariant();
+ }
+ }
+ return QAbstractTableModel::headerData(section, orientation, role);
+}
+
+QVariant CookieModel::data(const QModelIndex &index, int role) const
+{
+ QList<QNetworkCookie> lst;
+ if (m_cookieJar)
+ lst = m_cookieJar->allCookies();
+ if (index.row() < 0 || index.row() >= lst.size())
+ return QVariant();
+
+ switch (role) {
+ case Qt::DisplayRole:
+ case Qt::EditRole: {
+ QNetworkCookie cookie = lst.at(index.row());
+ switch (index.column()) {
+ case 0:
+ return cookie.domain();
+ case 1:
+ return cookie.name();
+ case 2:
+ return cookie.path();
+ case 3:
+ return cookie.isSecure();
+ case 4:
+ return cookie.expirationDate();
+ case 5:
+ return cookie.value();
+ }
+ }
+ case Qt::FontRole:{
+ QFont font;
+ font.setPointSize(10);
+ return font;
+ }
+ }
+
+ return QVariant();
+}
+
+int CookieModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : 6;
+}
+
+int CookieModel::rowCount(const QModelIndex &parent) const
+{
+ return (parent.isValid() || !m_cookieJar) ? 0 : m_cookieJar->allCookies().count();
+}
+
+bool CookieModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (parent.isValid() || !m_cookieJar)
+ return false;
+ int lastRow = row + count - 1;
+ beginRemoveRows(parent, row, lastRow);
+ QList<QNetworkCookie> lst = m_cookieJar->allCookies();
+ for (int i = lastRow; i >= row; --i) {
+ lst.removeAt(i);
+ }
+ m_cookieJar->setAllCookies(lst);
+ endRemoveRows();
+ return true;
+}
+
+void CookieModel::cookiesChanged()
+{
+ reset();
+}
+
+CookiesDialog::CookiesDialog(CookieJar *cookieJar, QWidget *parent) : QDialog(parent)
+{
+ setupUi(this);
+ setWindowFlags(Qt::Sheet);
+ CookieModel *model = new CookieModel(cookieJar, this);
+ m_proxyModel = new QSortFilterProxyModel(this);
+ connect(search, SIGNAL(textChanged(QString)),
+ m_proxyModel, SLOT(setFilterFixedString(QString)));
+ connect(removeButton, SIGNAL(clicked()), cookiesTable, SLOT(removeOne()));
+ connect(removeAllButton, SIGNAL(clicked()), cookiesTable, SLOT(removeAll()));
+ m_proxyModel->setSourceModel(model);
+ cookiesTable->verticalHeader()->hide();
+ cookiesTable->setSelectionBehavior(QAbstractItemView::SelectRows);
+ cookiesTable->setModel(m_proxyModel);
+ cookiesTable->setAlternatingRowColors(true);
+ cookiesTable->setTextElideMode(Qt::ElideMiddle);
+ cookiesTable->setShowGrid(false);
+ cookiesTable->setSortingEnabled(true);
+ QFont f = font();
+ f.setPointSize(10);
+ QFontMetrics fm(f);
+ int height = fm.height() + fm.height()/3;
+ cookiesTable->verticalHeader()->setDefaultSectionSize(height);
+ cookiesTable->verticalHeader()->setMinimumSectionSize(-1);
+ for (int i = 0; i < model->columnCount(); ++i){
+ int header = cookiesTable->horizontalHeader()->sectionSizeHint(i);
+ switch (i) {
+ case 0:
+ header = fm.width(QLatin1String("averagehost.domain.com"));
+ break;
+ case 1:
+ header = fm.width(QLatin1String("_session_id"));
+ break;
+ case 4:
+ header = fm.width(QDateTime::currentDateTime().toString(Qt::LocalDate));
+ break;
+ }
+ int buffer = fm.width(QLatin1String("xx"));
+ header += buffer;
+ cookiesTable->horizontalHeader()->resizeSection(i, header);
+ }
+ cookiesTable->horizontalHeader()->setStretchLastSection(true);
+}
+
+
+
+CookieExceptionsModel::CookieExceptionsModel(CookieJar *cookiejar, QObject *parent)
+ : QAbstractTableModel(parent)
+ , m_cookieJar(cookiejar)
+{
+ m_allowedCookies = m_cookieJar->allowedCookies();
+ m_blockedCookies = m_cookieJar->blockedCookies();
+ m_sessionCookies = m_cookieJar->allowForSessionCookies();
+}
+
+QVariant CookieExceptionsModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role == Qt::SizeHintRole) {
+ QFont font;
+ font.setPointSize(10);
+ QFontMetrics fm(font);
+ int height = fm.height() + fm.height()/3;
+ int width = fm.width(headerData(section, orientation, Qt::DisplayRole).toString());
+ return QSize(width, height);
+ }
+
+ if (orientation == Qt::Horizontal
+ && role == Qt::DisplayRole) {
+ switch (section) {
+ case 0:
+ return tr("Website");
+ case 1:
+ return tr("Status");
+ }
+ }
+ return QAbstractTableModel::headerData(section, orientation, role);
+}
+
+QVariant CookieExceptionsModel::data(const QModelIndex &index, int role) const
+{
+ if (index.row() < 0 || index.row() >= rowCount())
+ return QVariant();
+
+ switch (role) {
+ case Qt::DisplayRole:
+ case Qt::EditRole: {
+ int row = index.row();
+ if (row < m_allowedCookies.count()) {
+ switch (index.column()) {
+ case 0:
+ return m_allowedCookies.at(row);
+ case 1:
+ return tr("Allow");
+ }
+ }
+ row = row - m_allowedCookies.count();
+ if (row < m_blockedCookies.count()) {
+ switch (index.column()) {
+ case 0:
+ return m_blockedCookies.at(row);
+ case 1:
+ return tr("Block");
+ }
+ }
+ row = row - m_blockedCookies.count();
+ if (row < m_sessionCookies.count()) {
+ switch (index.column()) {
+ case 0:
+ return m_sessionCookies.at(row);
+ case 1:
+ return tr("Allow For Session");
+ }
+ }
+ }
+ case Qt::FontRole:{
+ QFont font;
+ font.setPointSize(10);
+ return font;
+ }
+ }
+ return QVariant();
+}
+
+int CookieExceptionsModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : 2;
+}
+
+int CookieExceptionsModel::rowCount(const QModelIndex &parent) const
+{
+ return (parent.isValid() || !m_cookieJar) ? 0 : m_allowedCookies.count() + m_blockedCookies.count() + m_sessionCookies.count();
+}
+
+bool CookieExceptionsModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (parent.isValid() || !m_cookieJar)
+ return false;
+
+ int lastRow = row + count - 1;
+ beginRemoveRows(parent, row, lastRow);
+ for (int i = lastRow; i >= row; --i) {
+ if (i < m_allowedCookies.count()) {
+ m_allowedCookies.removeAt(row);
+ continue;
+ }
+ i = i - m_allowedCookies.count();
+ if (i < m_blockedCookies.count()) {
+ m_blockedCookies.removeAt(row);
+ continue;
+ }
+ i = i - m_blockedCookies.count();
+ if (i < m_sessionCookies.count()) {
+ m_sessionCookies.removeAt(row);
+ continue;
+ }
+ }
+ m_cookieJar->setAllowedCookies(m_allowedCookies);
+ m_cookieJar->setBlockedCookies(m_blockedCookies);
+ m_cookieJar->setAllowForSessionCookies(m_sessionCookies);
+ endRemoveRows();
+ return true;
+}
+
+CookiesExceptionsDialog::CookiesExceptionsDialog(CookieJar *cookieJar, QWidget *parent)
+ : QDialog(parent)
+ , m_cookieJar(cookieJar)
+{
+ setupUi(this);
+ setWindowFlags(Qt::Sheet);
+ connect(removeButton, SIGNAL(clicked()), exceptionTable, SLOT(removeOne()));
+ connect(removeAllButton, SIGNAL(clicked()), exceptionTable, SLOT(removeAll()));
+ exceptionTable->verticalHeader()->hide();
+ exceptionTable->setSelectionBehavior(QAbstractItemView::SelectRows);
+ exceptionTable->setAlternatingRowColors(true);
+ exceptionTable->setTextElideMode(Qt::ElideMiddle);
+ exceptionTable->setShowGrid(false);
+ exceptionTable->setSortingEnabled(true);
+ m_exceptionsModel = new CookieExceptionsModel(cookieJar, this);
+ m_proxyModel = new QSortFilterProxyModel(this);
+ m_proxyModel->setSourceModel(m_exceptionsModel);
+ connect(search, SIGNAL(textChanged(QString)),
+ m_proxyModel, SLOT(setFilterFixedString(QString)));
+ exceptionTable->setModel(m_proxyModel);
+
+ CookieModel *cookieModel = new CookieModel(cookieJar, this);
+ domainLineEdit->setCompleter(new QCompleter(cookieModel, domainLineEdit));
+
+ connect(domainLineEdit, SIGNAL(textChanged(const QString &)),
+ this, SLOT(textChanged(const QString &)));
+ connect(blockButton, SIGNAL(clicked()), this, SLOT(block()));
+ connect(allowButton, SIGNAL(clicked()), this, SLOT(allow()));
+ connect(allowForSessionButton, SIGNAL(clicked()), this, SLOT(allowForSession()));
+
+ QFont f = font();
+ f.setPointSize(10);
+ QFontMetrics fm(f);
+ int height = fm.height() + fm.height()/3;
+ exceptionTable->verticalHeader()->setDefaultSectionSize(height);
+ exceptionTable->verticalHeader()->setMinimumSectionSize(-1);
+ for (int i = 0; i < m_exceptionsModel->columnCount(); ++i){
+ int header = exceptionTable->horizontalHeader()->sectionSizeHint(i);
+ switch (i) {
+ case 0:
+ header = fm.width(QLatin1String("averagebiglonghost.domain.com"));
+ break;
+ case 1:
+ header = fm.width(QLatin1String("Allow For Session"));
+ break;
+ }
+ int buffer = fm.width(QLatin1String("xx"));
+ header += buffer;
+ exceptionTable->horizontalHeader()->resizeSection(i, header);
+ }
+}
+
+void CookiesExceptionsDialog::textChanged(const QString &text)
+{
+ bool enabled = !text.isEmpty();
+ blockButton->setEnabled(enabled);
+ allowButton->setEnabled(enabled);
+ allowForSessionButton->setEnabled(enabled);
+}
+
+void CookiesExceptionsDialog::block()
+{
+ if (domainLineEdit->text().isEmpty())
+ return;
+ m_exceptionsModel->m_blockedCookies.append(domainLineEdit->text());
+ m_cookieJar->setBlockedCookies(m_exceptionsModel->m_blockedCookies);
+ m_exceptionsModel->reset();
+}
+
+void CookiesExceptionsDialog::allow()
+{
+ if (domainLineEdit->text().isEmpty())
+ return;
+ m_exceptionsModel->m_allowedCookies.append(domainLineEdit->text());
+ m_cookieJar->setAllowedCookies(m_exceptionsModel->m_allowedCookies);
+ m_exceptionsModel->reset();
+}
+
+void CookiesExceptionsDialog::allowForSession()
+{
+ if (domainLineEdit->text().isEmpty())
+ return;
+ m_exceptionsModel->m_sessionCookies.append(domainLineEdit->text());
+ m_cookieJar->setAllowForSessionCookies(m_exceptionsModel->m_sessionCookies);
+ m_exceptionsModel->reset();
+}
+
diff --git a/demos/browser/cookiejar.h b/demos/browser/cookiejar.h
new file mode 100644
index 0000000..ffcd4c1
--- /dev/null
+++ b/demos/browser/cookiejar.h
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef COOKIEJAR_H
+#define COOKIEJAR_H
+
+#include <QtNetwork/QNetworkCookieJar>
+
+#include <QtCore/QAbstractItemModel>
+#include <QtCore/QStringList>
+
+#include <QtGui/QDialog>
+#include <QtGui/QTableView>
+
+QT_BEGIN_NAMESPACE
+class QSortFilterProxyModel;
+class QKeyEvent;
+QT_END_NAMESPACE
+
+class AutoSaver;
+
+class CookieJar : public QNetworkCookieJar
+{
+ friend class CookieModel;
+ Q_OBJECT
+ Q_PROPERTY(AcceptPolicy acceptPolicy READ acceptPolicy WRITE setAcceptPolicy)
+ Q_PROPERTY(KeepPolicy keepPolicy READ keepPolicy WRITE setKeepPolicy)
+ Q_PROPERTY(QStringList blockedCookies READ blockedCookies WRITE setBlockedCookies)
+ Q_PROPERTY(QStringList allowedCookies READ allowedCookies WRITE setAllowedCookies)
+ Q_PROPERTY(QStringList allowForSessionCookies READ allowForSessionCookies WRITE setAllowForSessionCookies)
+ Q_ENUMS(KeepPolicy)
+ Q_ENUMS(AcceptPolicy)
+
+signals:
+ void cookiesChanged();
+
+public:
+ enum AcceptPolicy {
+ AcceptAlways,
+ AcceptNever,
+ AcceptOnlyFromSitesNavigatedTo
+ };
+
+ enum KeepPolicy {
+ KeepUntilExpire,
+ KeepUntilExit,
+ KeepUntilTimeLimit
+ };
+
+ CookieJar(QObject *parent = 0);
+ ~CookieJar();
+
+ QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const;
+ bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url);
+
+ AcceptPolicy acceptPolicy() const;
+ void setAcceptPolicy(AcceptPolicy policy);
+
+ KeepPolicy keepPolicy() const;
+ void setKeepPolicy(KeepPolicy policy);
+
+ QStringList blockedCookies() const;
+ QStringList allowedCookies() const;
+ QStringList allowForSessionCookies() const;
+
+ void setBlockedCookies(const QStringList &list);
+ void setAllowedCookies(const QStringList &list);
+ void setAllowForSessionCookies(const QStringList &list);
+
+public slots:
+ void clear();
+ void loadSettings();
+
+private slots:
+ void save();
+
+private:
+ void purgeOldCookies();
+ void load();
+ bool m_loaded;
+ AutoSaver *m_saveTimer;
+
+ AcceptPolicy m_acceptCookies;
+ KeepPolicy m_keepCookies;
+
+ QStringList m_exceptions_block;
+ QStringList m_exceptions_allow;
+ QStringList m_exceptions_allowForSession;
+};
+
+class CookieModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ CookieModel(CookieJar *jar, QObject *parent = 0);
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+
+private slots:
+ void cookiesChanged();
+
+private:
+ CookieJar *m_cookieJar;
+};
+
+#include "ui_cookies.h"
+#include "ui_cookiesexceptions.h"
+
+class CookiesDialog : public QDialog, public Ui_CookiesDialog
+{
+ Q_OBJECT
+
+public:
+ CookiesDialog(CookieJar *cookieJar, QWidget *parent = 0);
+
+private:
+ QSortFilterProxyModel *m_proxyModel;
+};
+
+class CookieExceptionsModel : public QAbstractTableModel
+{
+ Q_OBJECT
+ friend class CookiesExceptionsDialog;
+
+public:
+ CookieExceptionsModel(CookieJar *cookieJar, QObject *parent = 0);
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+
+private:
+ CookieJar *m_cookieJar;
+
+ // Domains we allow, Domains we block, Domains we allow for this session
+ QStringList m_allowedCookies;
+ QStringList m_blockedCookies;
+ QStringList m_sessionCookies;
+};
+
+class CookiesExceptionsDialog : public QDialog, public Ui_CookiesExceptionsDialog
+{
+ Q_OBJECT
+
+public:
+ CookiesExceptionsDialog(CookieJar *cookieJar, QWidget *parent = 0);
+
+private slots:
+ void block();
+ void allow();
+ void allowForSession();
+ void textChanged(const QString &text);
+
+private:
+ CookieExceptionsModel *m_exceptionsModel;
+ QSortFilterProxyModel *m_proxyModel;
+ CookieJar *m_cookieJar;
+};
+
+#endif // COOKIEJAR_H
+
diff --git a/demos/browser/cookies.ui b/demos/browser/cookies.ui
new file mode 100644
index 0000000..c4bccc5
--- /dev/null
+++ b/demos/browser/cookies.ui
@@ -0,0 +1,106 @@
+<ui version="4.0" >
+ <class>CookiesDialog</class>
+ <widget class="QDialog" name="CookiesDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>550</width>
+ <height>370</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Cookies</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>252</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1" >
+ <widget class="SearchLineEdit" name="search" />
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="EditTableView" name="cookiesTable" />
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QPushButton" name="removeButton" >
+ <property name="text" >
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeAllButton" >
+ <property name="text" >
+ <string>Remove &amp;All Cookies</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>SearchLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>searchlineedit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>EditTableView</class>
+ <extends>QTableView</extends>
+ <header>edittableview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>CookiesDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>472</x>
+ <y>329</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>461</x>
+ <y>356</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/demos/browser/cookiesexceptions.ui b/demos/browser/cookiesexceptions.ui
new file mode 100644
index 0000000..3d9ef62
--- /dev/null
+++ b/demos/browser/cookiesexceptions.ui
@@ -0,0 +1,184 @@
+<ui version="4.0" >
+ <class>CookiesExceptionsDialog</class>
+ <widget class="QDialog" name="CookiesExceptionsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>466</width>
+ <height>446</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Cookie Exceptions</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QGroupBox" name="newExceptionGroupBox" >
+ <property name="title" >
+ <string>New Exception</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Domain:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="domainLineEdit" />
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>81</width>
+ <height>25</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="blockButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Block</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="allowForSessionButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Allow For Session</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="allowButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Allow</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="ExceptionsGroupBox" >
+ <property name="title" >
+ <string>Exceptions</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" colspan="3" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>252</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="3" >
+ <widget class="SearchLineEdit" name="search" />
+ </item>
+ <item row="1" column="0" colspan="4" >
+ <widget class="EditTableView" name="exceptionTable" />
+ </item>
+ <item row="2" column="0" >
+ <widget class="QPushButton" name="removeButton" >
+ <property name="text" >
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QPushButton" name="removeAllButton" >
+ <property name="text" >
+ <string>Remove &amp;All</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" colspan="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>SearchLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>searchlineedit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>EditTableView</class>
+ <extends>QTableView</extends>
+ <header>edittableview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>CookiesExceptionsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>381</x>
+ <y>428</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>336</x>
+ <y>443</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/demos/browser/data/addtab.png b/demos/browser/data/addtab.png
new file mode 100644
index 0000000..20928fb
--- /dev/null
+++ b/demos/browser/data/addtab.png
Binary files differ
diff --git a/demos/browser/data/browser.svg b/demos/browser/data/browser.svg
new file mode 100644
index 0000000..4b0fa72
--- /dev/null
+++ b/demos/browser/data/browser.svg
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="48px"
+ height="48px"
+ id="svg2160"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ inkscape:export-filename="c:\icons\qtbrowser48.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:docbase="C:\icons"
+ sodipodi:docname="browser.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs2162"><linearGradient
+ id="linearGradient3808">
+ <stop
+ id="stop3810"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.54263568;" />
+ <stop
+ id="stop3812"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+</linearGradient>
+<inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective63" />
+<linearGradient
+ id="linearGradient3326">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.3137255;"
+ offset="0"
+ id="stop3328" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3330" />
+</linearGradient>
+<linearGradient
+ id="linearGradient3318">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.3137255;"
+ offset="0"
+ id="stop3320" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3322" />
+</linearGradient>
+<linearGradient
+ id="linearGradient3302">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.3137255;"
+ offset="0"
+ id="stop3304" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3306" />
+</linearGradient>
+<linearGradient
+ id="linearGradient3267">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3269" />
+ <stop
+ id="stop3275"
+ offset="0.79661018"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3271" />
+</linearGradient>
+<linearGradient
+ id="linearGradient3745">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.19587629;"
+ offset="0"
+ id="stop3747" />
+ <stop
+ style="stop-color:#7cb2ff;stop-opacity:0.07216495;"
+ offset="1"
+ id="stop3749" />
+</linearGradient>
+<linearGradient
+ inkscape:collect="always"
+ id="linearGradient3561">
+ <stop
+ style="stop-color:#b1d0ff;stop-opacity:1;"
+ offset="0"
+ id="stop3563" />
+ <stop
+ style="stop-color:#b1d0ff;stop-opacity:0;"
+ offset="1"
+ id="stop3565" />
+</linearGradient>
+<linearGradient
+ id="linearGradient3181">
+ <stop
+ style="stop-color:#4f7a33;stop-opacity:1;"
+ offset="0"
+ id="stop3183" />
+ <stop
+ style="stop-color:#204712;stop-opacity:1;"
+ offset="1"
+ id="stop3185" />
+</linearGradient>
+<linearGradient
+ id="linearGradient3143">
+ <stop
+ style="stop-color:#c1dbff;stop-opacity:1;"
+ offset="0"
+ id="stop3145" />
+ <stop
+ style="stop-color:#004e92;stop-opacity:1;"
+ offset="1"
+ id="stop3147" />
+</linearGradient>
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3143"
+ id="radialGradient3149"
+ cx="9.1428566"
+ cy="15.142858"
+ fx="9.1428566"
+ fy="15.142858"
+ r="20.121096"
+ gradientUnits="userSpaceOnUse" />
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3181"
+ id="radialGradient3187"
+ cx="10.739879"
+ cy="18.250999"
+ fx="10.739879"
+ fy="18.250999"
+ r="7.4191086"
+ gradientTransform="matrix(1.0504709,0,0,1.5077925,-0.3797113,-9.2677171)"
+ gradientUnits="userSpaceOnUse" />
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3181"
+ id="radialGradient3195"
+ cx="14.947268"
+ cy="35.920116"
+ fx="14.947268"
+ fy="35.920116"
+ r="6.0472684"
+ gradientTransform="matrix(1,0,0,0.7248478,0,9.8834985)"
+ gradientUnits="userSpaceOnUse" />
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3181"
+ id="radialGradient3203"
+ cx="34.227203"
+ cy="24.681196"
+ fx="34.227203"
+ fy="24.681196"
+ r="6.7517419"
+ gradientTransform="matrix(0.9941509,-0.1079997,0.2962199,2.7267411,-7.1108629,-38.921508)"
+ gradientUnits="userSpaceOnUse" />
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3561"
+ id="radialGradient3567"
+ cx="22.714285"
+ cy="23.571428"
+ fx="22.714285"
+ fy="23.571428"
+ r="19.828572"
+ gradientUnits="userSpaceOnUse" />
+<linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3745"
+ id="linearGradient3751"
+ x1="0.84126461"
+ y1="13.678415"
+ x2="31.397495"
+ y2="13.678415"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8791332,0.7829527,-0.6285195,1.0951445,14.147627,-10.49311)" />
+<filter
+ inkscape:collect="always"
+ id="filter4176">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.27747502"
+ id="feGaussianBlur4178" />
+</filter>
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3267"
+ id="radialGradient3273"
+ cx="22.714285"
+ cy="23.571428"
+ fx="22.714285"
+ fy="23.571428"
+ r="19.428572"
+ gradientUnits="userSpaceOnUse" />
+<inkscape:perspective
+ id="perspective136"
+ inkscape:persp3d-origin="138.6795 : 92.479329 : 1"
+ inkscape:vp_z="277.35901 : 138.71899 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 138.71899 : 1"
+ sodipodi:type="inkscape:persp3d" />
+
+
+
+
+
+
+
+
+
+
+<linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3808"
+ id="linearGradient3806"
+ x1="32.829472"
+ y1="32.055603"
+ x2="34.522324"
+ y2="-1.0290829"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8832227,0,0,1,-8.0103007,9.1923882)" />
+</defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="5.6568542"
+ inkscape:cx="30.924085"
+ inkscape:cy="24.59691"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1299"
+ inkscape:window-height="883"
+ inkscape:window-x="373"
+ inkscape:window-y="89"
+ showguides="false" />
+ <metadata
+ id="metadata2165">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Qt Browser</dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Jens Bache-Wiig</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:rights>
+ <cc:Agent>
+ <dc:title>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</dc:title>
+ </cc:Agent>
+ </dc:rights>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.78108437;fill:url(#radialGradient3273);fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3407"
+ sodipodi:cx="22.714285"
+ sodipodi:cy="23.571428"
+ sodipodi:rx="19.428572"
+ sodipodi:ry="19.428572"
+ d="M 42.142857,23.571428 A 19.428572,19.428572 0 1 1 3.2857132,23.571428 A 19.428572,19.428572 0 1 1 42.142857,23.571428 z"
+ transform="matrix(1.0818892,0,0,1.0409446,-2.4313375,0.4303723)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#radialGradient3149);fill-opacity:1;stroke:none;stroke-width:0.80000000000000004;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path2170"
+ sodipodi:cx="22.714285"
+ sodipodi:cy="23.571428"
+ sodipodi:rx="19.428572"
+ sodipodi:ry="19.428572"
+ d="M 42.142857 23.571428 A 19.428572 19.428572 0 1 1 3.2857132,23.571428 A 19.428572 19.428572 0 1 1 42.142857 23.571428 z" />
+ <path
+ d="M 26.602136,8.2160843 C 26.322653,8.1637524 26.048884,8.1512446 25.78375,8.1745351 L 25.783243,8.1743913 C 25.783243,8.1743913 23.973525,8.3138471 23.891496,8.3211793 C 22.239361,8.4705552 20.985434,10.008307 20.985434,12.131916 L 20.985434,37.174579 L 22.83515,39.126673 L 41.425135,33.998394 C 42.704203,33.746799 43.714709,33.629384 43.714709,31.78483 L 43.714709,11.392226 L 26.602136,8.2160843 z"
+ id="path2998"
+ style="fill:url(#linearGradient3806);fill-opacity:1"
+ sodipodi:nodetypes="cccsccccccc" />
+ <path
+ style="fill:url(#radialGradient3203);fill-opacity:1;fill-rule:evenodd;stroke:#1d3215;stroke-width:0.51392877000000003;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 37.535517,11.721122 C 32.782916,8.7478602 30.602351,6.3542385 32.09957,13.4346 C 32.320572,14.27055 33.291276,13.739232 33.291276,14.862228 C 33.291276,16.155819 32.607502,17.380765 31.797574,18.146663 C 30.959323,18.939344 31.011357,20.258984 31.797574,21.002459 C 33.06234,22.198469 33.942515,22.715936 35.572536,22.715936 C 36.6448,22.715936 37.003629,23.274262 37.23352,24.143834 C 37.362263,24.630808 38.410486,25.085663 38.894503,25.428942 C 38.938905,25.460433 38.139512,26.551348 38.139512,27.999158 C 38.139512,29.113512 38.405167,29.358325 38.743505,29.998215 C 38.949111,30.387072 36.418877,30.283794 36.025532,30.283794 C 35.005751,30.283794 34.181701,30.712163 33.15656,30.712163 C 32.264543,30.712163 31.099578,30.3566 31.344578,31.283323 C 31.763542,32.868074 32.552566,33.932342 32.552566,35.709806 C 32.552566,36.862272 31.047367,37.598377 30.287588,38.137232 C 29.30273,38.835721 29.133207,39.307154 28.475606,40.136289 C 28.132145,40.569341 26.990548,41.409612 28.475606,40.707448 C 29.476144,40.234375 31.192063,39.423774 32.09957,38.565601 C 33.257846,37.470293 34.527421,37.269266 35.723534,36.138176 C 36.659137,35.253436 37.512933,34.691155 38.29051,33.710749 C 39.024031,32.785889 39.498498,31.90347 39.498498,30.712163 C 39.498498,29.682482 39.308098,28.750366 39.951493,28.141948 C 40.902684,24.235856 42.225874,19.789742 39.751646,16.005086 C 38.569376,15.014407 37.717516,13.109859 37.535517,11.721122 z "
+ id="path3151"
+ sodipodi:nodetypes="ccsssssssssssssssssssccc" />
+ <path
+ style="fill:url(#radialGradient3187);fill-opacity:1;fill-rule:evenodd;stroke:#063a0a;stroke-width:0.51231807;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 14.777083,7.8630009 C 14.047432,8.4403746 12.751987,10.898939 13.27641,12.146301 C 13.709874,13.177316 14.920827,13.613143 15.827553,13.859622 C 16.568703,14.061091 17.049015,14.457271 17.478293,15.001835 C 17.832696,15.451415 17.971105,16.346745 18.078563,16.857932 C 18.298637,17.904845 18.947911,17.058563 17.62836,18.000145 C 17.234352,18.281296 14.875696,18.000145 14.476948,18.000145 C 11.976825,18.384083 14.297504,19.464893 14.92715,20.712903 C 15.204987,21.770261 15.377352,22.405336 15.377352,23.711213 C 15.377352,24.875672 15.377352,24.78389 15.377352,25.99564 C 15.377352,27.194757 15.044241,27.28063 13.876679,27.28063 C 13.023055,27.28063 12.647321,26.423969 11.625669,26.423969 C 10.400599,26.423969 11.303539,27.667106 11.475602,27.994513 C 12.006402,29.004538 11.662121,29.599737 10.875334,28.851174 C 9.855722,27.881096 8.8280305,26.760556 8.0240557,25.99564 C 2.8789379,25.807372 4.5677903,23.466499 3.9722395,18.999582 C 5.041259,16.526382 4.7558935,17.248897 7.2737194,12.574632 C 10.149914,9.5491592 13.589212,5.9532919 14.777083,7.8630009 z"
+ id="path3159"
+ sodipodi:nodetypes="csssssccsssssscccc" />
+ <path
+ style="fill:url(#radialGradient3195);fill-opacity:1;fill-rule:evenodd;stroke:#163c0c;stroke-width:0.59999999999999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 10.265966,34.571429 C 9.245427,35.081699 8.6225774,36.042538 9.980252,36.857143 C 10.637564,37.25153 11.478587,37.606311 12.265966,38 C 13.258976,38.496505 14.481138,39.018522 15.408823,39.714286 C 16.227572,40.328348 15.587589,39.928184 16.123109,38.857143 C 16.827927,37.447507 18.14516,38.79674 18.837395,39.142857 C 20.044787,39.746554 20.46001,38.652394 20.694537,37.714286 C 20.459863,35.791335 18.579948,34.625723 17.123109,33.285715 C 16.704922,32.588736 15.507117,31.689713 14.837395,31.857143 C 13.49505,33.304042 12.350312,33.960279 10.265966,34.571429 z "
+ id="path3161"
+ sodipodi:nodetypes="cssssscccc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:none;fill-opacity:1;stroke:url(#radialGradient3567);stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.6502732"
+ id="path3557"
+ sodipodi:cx="22.714285"
+ sodipodi:cy="23.571428"
+ sodipodi:rx="19.428572"
+ sodipodi:ry="19.428572"
+ d="M 42.142857 23.571428 A 19.428572 19.428572 0 1 1 3.2857132,23.571428 A 19.428572 19.428572 0 1 1 42.142857 23.571428 z"
+ transform="matrix(0.95317,0,0,0.95317,0.9922816,1.1752786)" />
+ <path
+ style="fill:url(#linearGradient3751);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 39.916926,27.786316 C 44.588637,26.790847 38.225604,13.201712 32.946381,8.5000566 C 18.135275,-0.40265528 10.844456,5.6490056 3.6645529,16.333771 C 5.7478288,18.189127 14.704728,33.158645 39.916926,27.786316 z"
+ id="path3578"
+ sodipodi:nodetypes="cccs" />
+ <path
+ d="M 45.902562,20.610592 C 46.007701,20.610592 46.120332,20.603354 46.240455,20.590275 L 45.609873,20.590275 C 45.697743,20.603608 45.798946,20.610592 45.902562,20.610592 z"
+ id="path3012"
+ style="fill:#0a6333" />
+ <path
+ sodipodi:type="arc"
+ style="fill:none;fill-opacity:1;stroke:#273e5e;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3818"
+ sodipodi:cx="22.714285"
+ sodipodi:cy="23.571428"
+ sodipodi:rx="19.428572"
+ sodipodi:ry="19.428572"
+ d="M 42.142857,23.571428 A 19.428572,19.428572 0 1 1 3.2857132,23.571428 A 19.428572,19.428572 0 1 1 42.142857,23.571428 z"
+ transform="matrix(0.9754581,0,0,0.9754581,0.3821951,0.7002631)" />
+ <g
+ transform="matrix(0.1269799,0,0,0.1269799,23.283534,9.5774104)"
+ id="g236">
+ <path
+ style="fill:#024c1c"
+ id="path238"
+ d="M 44.233,0.368 C 42.032,0.004 39.876,-0.083 37.788,0.079 L 37.784,0.078 C 37.784,0.078 23.532,1.048 22.886,1.099 C 9.875,2.138 0,12.834 0,27.605 L 0,201.792 L 14.567,215.37 L 160.968,190.766 C 171.041,189.016 178.999,177.133 178.999,164.303 L 178.999,22.46 L 44.233,0.368 z" />
+
+ <path
+ style="fill:#66b036"
+ id="path240"
+ d="M 179,164.304 C 179,177.134 171.042,189.017 160.969,190.767 L 14.567,215.37 L 14.567,26.683 C 14.567,9.52 28.263,-2.264 44.231,0.368 L 179,22.462 L 179,164.304 z" />
+
+ <g
+ id="g242">
+ <path
+ style="fill:#ffffff"
+ id="path244"
+ d="M 133.897,47.137 L 145.72,48.411 L 145.72,69.158 L 159.025,70.099 L 159.025,83.113 L 145.72,82.502 L 145.72,130.066 C 145.72,134.207 146.176,136.869 147.093,138.064 C 147.919,139.158 149.195,139.697 150.907,139.697 C 151.069,139.697 151.24,139.695 151.414,139.683 C 154.031,139.533 156.878,138.728 159.98,137.314 L 159.98,149.275 C 154.707,151.591 149.532,152.966 144.452,153.398 C 143.716,153.457 143.005,153.486 142.317,153.486 C 137.716,153.486 134.199,152.152 131.797,149.451 C 128.998,146.318 127.598,141.285 127.598,134.387 L 127.598,81.661 L 121.209,81.368 L 121.209,67.424 L 129,67.985 L 133.897,47.137 z" />
+
+ </g>
+
+ <polygon
+ style="fill:#0a6333"
+ id="polygon246"
+ points="159.027,83.112 145.722,82.501 145.722,82.785 152.854,83.112 159.027,83.112 " />
+
+ <path
+ style="fill:#024c1c"
+ id="path248"
+ d="M 148.488,139.21 C 149.168,139.548 149.96,139.696 150.908,139.696 C 151.07,139.696 151.241,139.694 151.415,139.682 C 154.032,139.532 156.879,138.727 159.981,137.313 L 153.806,137.313 C 151.938,138.169 150.178,138.808 148.488,139.21 z" />
+
+ <path
+ style="fill:#024c1c"
+ id="path250"
+ d="M 133.897,47.137 L 127.723,47.137 L 122.93,67.549 L 129,67.985 L 133.897,47.137 z M 131.799,149.45 C 129,146.317 127.6,141.284 127.6,134.386 L 127.6,81.661 L 121.211,81.368 L 121.211,67.424 L 115.03,67.424 L 115.03,70.539 C 115.926,73.897 116.63,77.539 117.149,81.465 L 121.426,81.661 L 121.426,134.386 C 121.426,141.284 122.827,146.318 125.625,149.45 C 128.029,152.151 131.541,153.485 136.141,153.485 L 142.318,153.485 C 137.718,153.485 134.2,152.151 131.799,149.45 z" />
+
+ <path
+ style="fill:#0a6333"
+ id="path252"
+ d="M 102.954,170.419 C 103.782,170.419 104.669,170.362 105.615,170.259 L 100.649,170.259 C 101.341,170.364 102.138,170.419 102.954,170.419 z" />
+
+ <path
+ style="fill:#ffffff"
+ id="path254"
+ d="M 112.036,139.78 C 107.81,149.749 101.365,156.27 92.542,159.288 C 93.43,163.856 94.778,166.929 96.567,168.55 C 97.955,169.796 100.094,170.419 102.958,170.419 C 103.782,170.419 104.671,170.362 105.615,170.259 L 105.615,183.736 L 99.497,184.539 C 97.692,184.771 95.98,184.889 94.361,184.889 C 89.001,184.889 84.665,183.59 81.402,180.961 C 77.085,177.496 73.899,170.805 71.857,160.908 C 62.48,158.91 55.166,152.945 50.103,142.937 C 44.965,132.769 42.349,117.895 42.349,98.441 C 42.349,77.466 45.927,61.985 52.971,52.169 C 58.912,43.885 67.202,39.812 77.634,39.812 C 79.306,39.812 81.033,39.916 82.809,40.124 C 95.081,41.539 103.977,47.329 109.77,57.362 C 115.453,67.177 118.243,81.244 118.243,99.721 C 118.242,116.643 116.186,129.954 112.036,139.78 z M 93.582,135.933 C 95.996,129.724 97.189,117.54 97.189,99.37 C 97.189,83.054 96.007,71.837 93.608,65.682 C 91.21,59.496 87.622,56.153 82.808,55.731 C 82.441,55.7 82.075,55.681 81.724,55.681 C 77.264,55.681 73.84,58.283 71.447,63.508 C 68.863,69.201 67.555,81.003 67.555,98.866 C 67.555,116.129 68.826,128.379 71.388,135.569 C 73.804,142.419 77.423,145.813 82.174,145.813 C 82.384,145.813 82.593,145.805 82.809,145.79 C 87.566,145.489 91.148,142.202 93.582,135.933" />
+
+ <path
+ style="fill:#024c1c"
+ id="path256"
+ d="M 84.708,183.003 C 84.59,182.95 84.477,182.896 84.361,182.839 C 84.349,182.835 84.336,182.829 84.323,182.821 C 84.218,182.77 84.115,182.716 84.011,182.663 C 83.991,182.653 83.971,182.642 83.948,182.63 C 83.854,182.579 83.761,182.528 83.667,182.476 C 83.636,182.46 83.609,182.443 83.579,182.427 C 83.494,182.38 83.412,182.331 83.328,182.284 C 83.286,182.263 83.25,182.239 83.209,182.214 C 83.137,182.171 83.062,182.128 82.994,182.083 C 82.943,182.054 82.897,182.024 82.848,181.993 C 82.785,181.954 82.726,181.915 82.663,181.876 C 82.606,181.837 82.552,181.798 82.492,181.759 C 82.442,181.726 82.392,181.693 82.342,181.659 C 82.272,181.612 82.206,181.563 82.141,181.518 C 82.101,181.489 82.061,181.463 82.021,181.432 C 81.943,181.377 81.866,181.319 81.79,181.26 C 81.764,181.239 81.735,181.221 81.708,181.199 C 81.607,181.121 81.505,181.039 81.402,180.959 C 77.085,177.494 73.899,170.803 71.857,160.906 C 62.48,158.908 55.166,152.943 50.103,142.935 C 44.965,132.767 42.349,117.893 42.349,98.439 C 42.349,77.464 45.927,61.983 52.971,52.167 C 58.912,43.883 67.202,39.81 77.634,39.81 C 77.67,39.81 71.114,39.806 71.114,39.806 L 71.114,39.81 C 60.694,39.818 52.411,43.89 46.476,52.167 C 39.434,61.984 35.855,77.465 35.855,98.439 C 35.855,117.892 38.469,132.767 43.609,142.935 C 48.671,152.943 55.983,158.908 65.361,160.906 C 67.403,170.802 70.588,177.494 74.904,180.959 C 78.168,183.588 82.507,184.887 87.867,184.887 C 87.967,184.887 88.07,184.887 88.17,184.885 L 93.861,184.885 C 90.361,184.828 87.306,184.203 84.716,183.006 C 84.712,183.007 84.708,183.007 84.708,183.003 z M 87.113,65.681 C 89.511,71.837 90.69,83.054 90.69,99.369 C 90.69,117.539 89.502,129.723 87.083,135.932 C 85.142,140.942 82.439,144.047 79.013,145.248 C 79.999,145.621 81.058,145.81 82.173,145.81 C 82.383,145.81 82.592,145.802 82.808,145.787 C 87.567,145.488 91.149,142.201 93.582,135.932 C 95.996,129.723 97.189,117.539 97.189,99.369 C 97.189,83.053 96.007,71.836 93.608,65.681 C 91.21,59.495 87.622,56.152 82.808,55.73 C 82.441,55.699 82.075,55.68 81.724,55.68 C 80.601,55.68 79.549,55.845 78.556,56.173 L 78.556,56.175 L 78.556,56.175 C 82.254,57.322 85.104,60.5 87.113,65.681 z" />
+
+</g>
+ </g>
+</svg>
diff --git a/demos/browser/data/closetab.png b/demos/browser/data/closetab.png
new file mode 100644
index 0000000..ab9d669
--- /dev/null
+++ b/demos/browser/data/closetab.png
Binary files differ
diff --git a/demos/browser/data/data.qrc b/demos/browser/data/data.qrc
new file mode 100644
index 0000000..c7d0294
--- /dev/null
+++ b/demos/browser/data/data.qrc
@@ -0,0 +1,11 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>addtab.png</file>
+ <file>closetab.png</file>
+ <file>history.png</file>
+ <file>browser.svg</file>
+ <file>defaultbookmarks.xbel</file>
+ <file>loading.gif</file>
+ <file>defaulticon.png</file>
+</qresource>
+</RCC>
diff --git a/demos/browser/data/defaultbookmarks.xbel b/demos/browser/data/defaultbookmarks.xbel
new file mode 100644
index 0000000..a168244
--- /dev/null
+++ b/demos/browser/data/defaultbookmarks.xbel
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE xbel>
+<xbel version="1.0">
+ <folder folded="yes">
+ <title>Bookmarks Bar</title>
+ <bookmark href="http://qtsoftware.com/">
+ <title>Qt Software</title>
+ </bookmark>
+ <bookmark href="http://webkit.org/">
+ <title>WebKit.org</title>
+ </bookmark>
+ <bookmark href="http://doc.trolltech.com/">
+ <title>Qt Documentation</title>
+ </bookmark>
+ <bookmark href="http://doc.trolltech.com/qq/">
+ <title>Qt Quarterly</title>
+ </bookmark>
+ <bookmark href="http://labs.trolltech.com/">
+ <title>Qt Labs</title>
+ </bookmark>
+ <bookmark href="http://www.qtcentre.org/">
+ <title>Qt Centre</title>
+ </bookmark>
+ <bookmark href="http://qt-apps.org/">
+ <title>Qt-Apps.org</title>
+ </bookmark>
+ <bookmark href="http://qtnode.net/">
+ <title>qtnode</title>
+ </bookmark>
+ <bookmark href="http://xkcd.com/">
+ <title>xkcd</title>
+ </bookmark>
+ </folder>
+ <folder folded="yes">
+ <title>Bookmarks Menu</title>
+ <bookmark href="http://reddit.com/">
+ <title>reddit.com: what's new online!</title>
+ </bookmark>
+ </folder>
+</xbel>
diff --git a/demos/browser/data/defaulticon.png b/demos/browser/data/defaulticon.png
new file mode 100644
index 0000000..01a0920
--- /dev/null
+++ b/demos/browser/data/defaulticon.png
Binary files differ
diff --git a/demos/browser/data/history.png b/demos/browser/data/history.png
new file mode 100644
index 0000000..552a1cb
--- /dev/null
+++ b/demos/browser/data/history.png
Binary files differ
diff --git a/demos/browser/data/loading.gif b/demos/browser/data/loading.gif
new file mode 100644
index 0000000..c1545eb
--- /dev/null
+++ b/demos/browser/data/loading.gif
Binary files differ
diff --git a/demos/browser/downloaditem.ui b/demos/browser/downloaditem.ui
new file mode 100644
index 0000000..4a0a0fd
--- /dev/null
+++ b/demos/browser/downloaditem.ui
@@ -0,0 +1,134 @@
+<ui version="4.0" >
+ <class>DownloadItem</class>
+ <widget class="QWidget" name="DownloadItem" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>423</width>
+ <height>110</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="fileIcon" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Minimum" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Ico</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2" >
+ <item>
+ <widget class="SqueezeLabel" native="1" name="fileNameLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" stdset="0" >
+ <string>Filename</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="progressBar" >
+ <property name="value" >
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="SqueezeLabel" native="1" name="downloadInfoLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" stdset="0" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>17</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="tryAgainButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Try Again</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="stopButton" >
+ <property name="text" >
+ <string>Stop</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="openButton" >
+ <property name="text" >
+ <string>Open</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>17</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>SqueezeLabel</class>
+ <extends>QWidget</extends>
+ <header>squeezelabel.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/demos/browser/downloadmanager.cpp b/demos/browser/downloadmanager.cpp
new file mode 100644
index 0000000..af31391
--- /dev/null
+++ b/demos/browser/downloadmanager.cpp
@@ -0,0 +1,579 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "downloadmanager.h"
+
+#include "autosaver.h"
+#include "browserapplication.h"
+#include "networkaccessmanager.h"
+
+#include <math.h>
+
+#include <QtCore/QMetaEnum>
+#include <QtCore/QSettings>
+
+#include <QtGui/QDesktopServices>
+#include <QtGui/QFileDialog>
+#include <QtGui/QHeaderView>
+#include <QtGui/QFileIconProvider>
+
+#include <QtCore/QDebug>
+
+#include <QtWebKit/QWebSettings>
+
+/*!
+ DownloadItem is a widget that is displayed in the download manager list.
+ It moves the data from the QNetworkReply into the QFile as well
+ as update the information/progressbar and report errors.
+ */
+DownloadItem::DownloadItem(QNetworkReply *reply, bool requestFileName, QWidget *parent)
+ : QWidget(parent)
+ , m_reply(reply)
+ , m_requestFileName(requestFileName)
+ , m_bytesReceived(0)
+{
+ setupUi(this);
+ QPalette p = downloadInfoLabel->palette();
+ p.setColor(QPalette::Text, Qt::darkGray);
+ downloadInfoLabel->setPalette(p);
+ progressBar->setMaximum(0);
+ tryAgainButton->hide();
+ connect(stopButton, SIGNAL(clicked()), this, SLOT(stop()));
+ connect(openButton, SIGNAL(clicked()), this, SLOT(open()));
+ connect(tryAgainButton, SIGNAL(clicked()), this, SLOT(tryAgain()));
+
+ init();
+}
+
+void DownloadItem::init()
+{
+ if (!m_reply)
+ return;
+
+ // attach to the m_reply
+ m_url = m_reply->url();
+ m_reply->setParent(this);
+ connect(m_reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead()));
+ connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ this, SLOT(error(QNetworkReply::NetworkError)));
+ connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)),
+ this, SLOT(downloadProgress(qint64, qint64)));
+ connect(m_reply, SIGNAL(metaDataChanged()),
+ this, SLOT(metaDataChanged()));
+ connect(m_reply, SIGNAL(finished()),
+ this, SLOT(finished()));
+
+ // reset info
+ downloadInfoLabel->clear();
+ progressBar->setValue(0);
+ getFileName();
+
+ // start timer for the download estimation
+ m_downloadTime.start();
+
+ if (m_reply->error() != QNetworkReply::NoError) {
+ error(m_reply->error());
+ finished();
+ }
+}
+
+void DownloadItem::getFileName()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("downloadmanager"));
+ QString defaultLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
+ QString downloadDirectory = settings.value(QLatin1String("downloadDirectory"), defaultLocation).toString();
+ if (!downloadDirectory.isEmpty())
+ downloadDirectory += QLatin1Char('/');
+
+ QString defaultFileName = saveFileName(downloadDirectory);
+ QString fileName = defaultFileName;
+ if (m_requestFileName) {
+ fileName = QFileDialog::getSaveFileName(this, tr("Save File"), defaultFileName);
+ if (fileName.isEmpty()) {
+ m_reply->close();
+ fileNameLabel->setText(tr("Download canceled: %1").arg(QFileInfo(defaultFileName).fileName()));
+ return;
+ }
+ }
+ m_output.setFileName(fileName);
+ fileNameLabel->setText(QFileInfo(m_output.fileName()).fileName());
+ if (m_requestFileName)
+ downloadReadyRead();
+}
+
+QString DownloadItem::saveFileName(const QString &directory) const
+{
+ // Move this function into QNetworkReply to also get file name sent from the server
+ QString path = m_url.path();
+ QFileInfo info(path);
+ QString baseName = info.completeBaseName();
+ QString endName = info.suffix();
+
+ if (baseName.isEmpty()) {
+ baseName = QLatin1String("unnamed_download");
+ qDebug() << "DownloadManager:: downloading unknown file:" << m_url;
+ }
+ QString name = directory + baseName + QLatin1Char('.') + endName;
+ if (QFile::exists(name)) {
+ // already exists, don't overwrite
+ int i = 1;
+ do {
+ name = directory + baseName + QLatin1Char('-') + QString::number(i++) + QLatin1Char('.') + endName;
+ } while (QFile::exists(name));
+ }
+ return name;
+}
+
+
+void DownloadItem::stop()
+{
+ setUpdatesEnabled(false);
+ stopButton->setEnabled(false);
+ stopButton->hide();
+ tryAgainButton->setEnabled(true);
+ tryAgainButton->show();
+ setUpdatesEnabled(true);
+ m_reply->abort();
+}
+
+void DownloadItem::open()
+{
+ QFileInfo info(m_output);
+ QUrl url = QUrl::fromLocalFile(info.absolutePath());
+ QDesktopServices::openUrl(url);
+}
+
+void DownloadItem::tryAgain()
+{
+ if (!tryAgainButton->isEnabled())
+ return;
+
+ tryAgainButton->setEnabled(false);
+ tryAgainButton->setVisible(false);
+ stopButton->setEnabled(true);
+ stopButton->setVisible(true);
+ progressBar->setVisible(true);
+
+ QNetworkReply *r = BrowserApplication::networkAccessManager()->get(QNetworkRequest(m_url));
+ if (m_reply)
+ m_reply->deleteLater();
+ if (m_output.exists())
+ m_output.remove();
+ m_reply = r;
+ init();
+ emit statusChanged();
+}
+
+void DownloadItem::downloadReadyRead()
+{
+ if (m_requestFileName && m_output.fileName().isEmpty())
+ return;
+ if (!m_output.isOpen()) {
+ // in case someone else has already put a file there
+ if (!m_requestFileName)
+ getFileName();
+ if (!m_output.open(QIODevice::WriteOnly)) {
+ downloadInfoLabel->setText(tr("Error opening save file: %1")
+ .arg(m_output.errorString()));
+ stopButton->click();
+ emit statusChanged();
+ return;
+ }
+ emit statusChanged();
+ }
+ if (-1 == m_output.write(m_reply->readAll())) {
+ downloadInfoLabel->setText(tr("Error saving: %1")
+ .arg(m_output.errorString()));
+ stopButton->click();
+ }
+}
+
+void DownloadItem::error(QNetworkReply::NetworkError)
+{
+ qDebug() << "DownloadItem::error" << m_reply->errorString() << m_url;
+ downloadInfoLabel->setText(tr("Network Error: %1").arg(m_reply->errorString()));
+ tryAgainButton->setEnabled(true);
+ tryAgainButton->setVisible(true);
+}
+
+void DownloadItem::metaDataChanged()
+{
+ qDebug() << "DownloadItem::metaDataChanged: not handled.";
+}
+
+void DownloadItem::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ m_bytesReceived = bytesReceived;
+ if (bytesTotal == -1) {
+ progressBar->setValue(0);
+ progressBar->setMaximum(0);
+ } else {
+ progressBar->setValue(bytesReceived);
+ progressBar->setMaximum(bytesTotal);
+ }
+ updateInfoLabel();
+}
+
+void DownloadItem::updateInfoLabel()
+{
+ if (m_reply->error() == QNetworkReply::NoError)
+ return;
+
+ qint64 bytesTotal = progressBar->maximum();
+ bool running = !downloadedSuccessfully();
+
+ // update info label
+ double speed = m_bytesReceived * 1000.0 / m_downloadTime.elapsed();
+ double timeRemaining = ((double)(bytesTotal - m_bytesReceived)) / speed;
+ QString timeRemainingString = tr("seconds");
+ if (timeRemaining > 60) {
+ timeRemaining = timeRemaining / 60;
+ timeRemainingString = tr("minutes");
+ }
+ timeRemaining = floor(timeRemaining);
+
+ // When downloading the eta should never be 0
+ if (timeRemaining == 0)
+ timeRemaining = 1;
+
+ QString info;
+ if (running) {
+ QString remaining;
+ if (bytesTotal != 0)
+ remaining = tr("- %4 %5 remaining")
+ .arg(timeRemaining)
+ .arg(timeRemainingString);
+ info = QString(tr("%1 of %2 (%3/sec) %4"))
+ .arg(dataString(m_bytesReceived))
+ .arg(bytesTotal == 0 ? tr("?") : dataString(bytesTotal))
+ .arg(dataString((int)speed))
+ .arg(remaining);
+ } else {
+ if (m_bytesReceived == bytesTotal)
+ info = dataString(m_output.size());
+ else
+ info = tr("%1 of %2 - Stopped")
+ .arg(dataString(m_bytesReceived))
+ .arg(dataString(bytesTotal));
+ }
+ downloadInfoLabel->setText(info);
+}
+
+QString DownloadItem::dataString(int size) const
+{
+ QString unit;
+ if (size < 1024) {
+ unit = tr("bytes");
+ } else if (size < 1024*1024) {
+ size /= 1024;
+ unit = tr("kB");
+ } else {
+ size /= 1024*1024;
+ unit = tr("MB");
+ }
+ return QString(QLatin1String("%1 %2")).arg(size).arg(unit);
+}
+
+bool DownloadItem::downloading() const
+{
+ return (progressBar->isVisible());
+}
+
+bool DownloadItem::downloadedSuccessfully() const
+{
+ return (stopButton->isHidden() && tryAgainButton->isHidden());
+}
+
+void DownloadItem::finished()
+{
+ progressBar->hide();
+ stopButton->setEnabled(false);
+ stopButton->hide();
+ m_output.close();
+ updateInfoLabel();
+ emit statusChanged();
+}
+
+/*!
+ DownloadManager is a Dialog that contains a list of DownloadItems
+
+ It is a basic download manager. It only downloads the file, doesn't do BitTorrent,
+ extract zipped files or anything fancy.
+ */
+DownloadManager::DownloadManager(QWidget *parent)
+ : QDialog(parent)
+ , m_autoSaver(new AutoSaver(this))
+ , m_manager(BrowserApplication::networkAccessManager())
+ , m_iconProvider(0)
+ , m_removePolicy(Never)
+{
+ setupUi(this);
+ downloadsView->setShowGrid(false);
+ downloadsView->verticalHeader()->hide();
+ downloadsView->horizontalHeader()->hide();
+ downloadsView->setAlternatingRowColors(true);
+ downloadsView->horizontalHeader()->setStretchLastSection(true);
+ m_model = new DownloadModel(this);
+ downloadsView->setModel(m_model);
+ connect(cleanupButton, SIGNAL(clicked()), this, SLOT(cleanup()));
+ load();
+}
+
+DownloadManager::~DownloadManager()
+{
+ m_autoSaver->changeOccurred();
+ m_autoSaver->saveIfNeccessary();
+ if (m_iconProvider)
+ delete m_iconProvider;
+}
+
+int DownloadManager::activeDownloads() const
+{
+ int count = 0;
+ for (int i = 0; i < m_downloads.count(); ++i) {
+ if (m_downloads.at(i)->stopButton->isEnabled())
+ ++count;
+ }
+ return count;
+}
+
+void DownloadManager::download(const QNetworkRequest &request, bool requestFileName)
+{
+ if (request.url().isEmpty())
+ return;
+ handleUnsupportedContent(m_manager->get(request), requestFileName);
+}
+
+void DownloadManager::handleUnsupportedContent(QNetworkReply *reply, bool requestFileName)
+{
+ if (!reply || reply->url().isEmpty())
+ return;
+ QVariant header = reply->header(QNetworkRequest::ContentLengthHeader);
+ bool ok;
+ int size = header.toInt(&ok);
+ if (ok && size == 0)
+ return;
+
+ qDebug() << "DownloadManager::handleUnsupportedContent" << reply->url() << "requestFileName" << requestFileName;
+ DownloadItem *item = new DownloadItem(reply, requestFileName, this);
+ addItem(item);
+}
+
+void DownloadManager::addItem(DownloadItem *item)
+{
+ connect(item, SIGNAL(statusChanged()), this, SLOT(updateRow()));
+ int row = m_downloads.count();
+ m_model->beginInsertRows(QModelIndex(), row, row);
+ m_downloads.append(item);
+ m_model->endInsertRows();
+ updateItemCount();
+ if (row == 0)
+ show();
+ downloadsView->setIndexWidget(m_model->index(row, 0), item);
+ QIcon icon = style()->standardIcon(QStyle::SP_FileIcon);
+ item->fileIcon->setPixmap(icon.pixmap(48, 48));
+ downloadsView->setRowHeight(row, item->sizeHint().height());
+}
+
+void DownloadManager::updateRow()
+{
+ DownloadItem *item = qobject_cast<DownloadItem*>(sender());
+ int row = m_downloads.indexOf(item);
+ if (-1 == row)
+ return;
+ if (!m_iconProvider)
+ m_iconProvider = new QFileIconProvider();
+ QIcon icon = m_iconProvider->icon(item->m_output.fileName());
+ if (icon.isNull())
+ icon = style()->standardIcon(QStyle::SP_FileIcon);
+ item->fileIcon->setPixmap(icon.pixmap(48, 48));
+ downloadsView->setRowHeight(row, item->minimumSizeHint().height());
+
+ bool remove = false;
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (!item->downloading()
+ && globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled))
+ remove = true;
+
+ if (item->downloadedSuccessfully()
+ && removePolicy() == DownloadManager::SuccessFullDownload) {
+ remove = true;
+ }
+ if (remove)
+ m_model->removeRow(row);
+
+ cleanupButton->setEnabled(m_downloads.count() - activeDownloads() > 0);
+}
+
+DownloadManager::RemovePolicy DownloadManager::removePolicy() const
+{
+ return m_removePolicy;
+}
+
+void DownloadManager::setRemovePolicy(RemovePolicy policy)
+{
+ if (policy == m_removePolicy)
+ return;
+ m_removePolicy = policy;
+ m_autoSaver->changeOccurred();
+}
+
+void DownloadManager::save() const
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("downloadmanager"));
+ QMetaEnum removePolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("RemovePolicy"));
+ settings.setValue(QLatin1String("removeDownloadsPolicy"), QLatin1String(removePolicyEnum.valueToKey(m_removePolicy)));
+ settings.setValue(QLatin1String("size"), size());
+ if (m_removePolicy == Exit)
+ return;
+
+ for (int i = 0; i < m_downloads.count(); ++i) {
+ QString key = QString(QLatin1String("download_%1_")).arg(i);
+ settings.setValue(key + QLatin1String("url"), m_downloads[i]->m_url);
+ settings.setValue(key + QLatin1String("location"), QFileInfo(m_downloads[i]->m_output).filePath());
+ settings.setValue(key + QLatin1String("done"), m_downloads[i]->downloadedSuccessfully());
+ }
+ int i = m_downloads.count();
+ QString key = QString(QLatin1String("download_%1_")).arg(i);
+ while (settings.contains(key + QLatin1String("url"))) {
+ settings.remove(key + QLatin1String("url"));
+ settings.remove(key + QLatin1String("location"));
+ settings.remove(key + QLatin1String("done"));
+ key = QString(QLatin1String("download_%1_")).arg(++i);
+ }
+}
+
+void DownloadManager::load()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("downloadmanager"));
+ QSize size = settings.value(QLatin1String("size")).toSize();
+ if (size.isValid())
+ resize(size);
+ QByteArray value = settings.value(QLatin1String("removeDownloadsPolicy"), QLatin1String("Never")).toByteArray();
+ QMetaEnum removePolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("RemovePolicy"));
+ m_removePolicy = removePolicyEnum.keyToValue(value) == -1 ?
+ Never :
+ static_cast<RemovePolicy>(removePolicyEnum.keyToValue(value));
+
+ int i = 0;
+ QString key = QString(QLatin1String("download_%1_")).arg(i);
+ while (settings.contains(key + QLatin1String("url"))) {
+ QUrl url = settings.value(key + QLatin1String("url")).toUrl();
+ QString fileName = settings.value(key + QLatin1String("location")).toString();
+ bool done = settings.value(key + QLatin1String("done"), true).toBool();
+ if (!url.isEmpty() && !fileName.isEmpty()) {
+ DownloadItem *item = new DownloadItem(0, this);
+ item->m_output.setFileName(fileName);
+ item->fileNameLabel->setText(QFileInfo(item->m_output.fileName()).fileName());
+ item->m_url = url;
+ item->stopButton->setVisible(false);
+ item->stopButton->setEnabled(false);
+ item->tryAgainButton->setVisible(!done);
+ item->tryAgainButton->setEnabled(!done);
+ item->progressBar->setVisible(!done);
+ addItem(item);
+ }
+ key = QString(QLatin1String("download_%1_")).arg(++i);
+ }
+ cleanupButton->setEnabled(m_downloads.count() - activeDownloads() > 0);
+}
+
+void DownloadManager::cleanup()
+{
+ if (m_downloads.isEmpty())
+ return;
+ m_model->removeRows(0, m_downloads.count());
+ updateItemCount();
+ if (m_downloads.isEmpty() && m_iconProvider) {
+ delete m_iconProvider;
+ m_iconProvider = 0;
+ }
+ m_autoSaver->changeOccurred();
+}
+
+void DownloadManager::updateItemCount()
+{
+ int count = m_downloads.count();
+ itemCount->setText(count == 1 ? tr("1 Download") : tr("%1 Downloads").arg(count));
+}
+
+DownloadModel::DownloadModel(DownloadManager *downloadManager, QObject *parent)
+ : QAbstractListModel(parent)
+ , m_downloadManager(downloadManager)
+{
+}
+
+QVariant DownloadModel::data(const QModelIndex &index, int role) const
+{
+ if (index.row() < 0 || index.row() >= rowCount(index.parent()))
+ return QVariant();
+ if (role == Qt::ToolTipRole)
+ if (!m_downloadManager->m_downloads.at(index.row())->downloadedSuccessfully())
+ return m_downloadManager->m_downloads.at(index.row())->downloadInfoLabel->text();
+ return QVariant();
+}
+
+int DownloadModel::rowCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : m_downloadManager->m_downloads.count();
+}
+
+bool DownloadModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (parent.isValid())
+ return false;
+
+ int lastRow = row + count - 1;
+ for (int i = lastRow; i >= row; --i) {
+ if (m_downloadManager->m_downloads.at(i)->downloadedSuccessfully()
+ || m_downloadManager->m_downloads.at(i)->tryAgainButton->isEnabled()) {
+ beginRemoveRows(parent, i, i);
+ m_downloadManager->m_downloads.takeAt(i)->deleteLater();
+ endRemoveRows();
+ }
+ }
+ m_downloadManager->m_autoSaver->changeOccurred();
+ return true;
+}
+
diff --git a/demos/browser/downloadmanager.h b/demos/browser/downloadmanager.h
new file mode 100644
index 0000000..85318da
--- /dev/null
+++ b/demos/browser/downloadmanager.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DOWNLOADMANAGER_H
+#define DOWNLOADMANAGER_H
+
+#include "ui_downloads.h"
+#include "ui_downloaditem.h"
+
+#include <QtNetwork/QNetworkReply>
+
+#include <QtCore/QFile>
+#include <QtCore/QTime>
+
+class DownloadItem : public QWidget, public Ui_DownloadItem
+{
+ Q_OBJECT
+
+signals:
+ void statusChanged();
+
+public:
+ DownloadItem(QNetworkReply *reply = 0, bool requestFileName = false, QWidget *parent = 0);
+ bool downloading() const;
+ bool downloadedSuccessfully() const;
+
+ QUrl m_url;
+
+ QFile m_output;
+ QNetworkReply *m_reply;
+
+private slots:
+ void stop();
+ void tryAgain();
+ void open();
+
+ void downloadReadyRead();
+ void error(QNetworkReply::NetworkError code);
+ void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
+ void metaDataChanged();
+ void finished();
+
+private:
+ void getFileName();
+ void init();
+ void updateInfoLabel();
+ QString dataString(int size) const;
+
+ QString saveFileName(const QString &directory) const;
+
+ bool m_requestFileName;
+ qint64 m_bytesReceived;
+ QTime m_downloadTime;
+};
+
+class AutoSaver;
+class DownloadModel;
+QT_BEGIN_NAMESPACE
+class QFileIconProvider;
+QT_END_NAMESPACE
+
+class DownloadManager : public QDialog, public Ui_DownloadDialog
+{
+ Q_OBJECT
+ Q_PROPERTY(RemovePolicy removePolicy READ removePolicy WRITE setRemovePolicy)
+ Q_ENUMS(RemovePolicy)
+
+public:
+ enum RemovePolicy {
+ Never,
+ Exit,
+ SuccessFullDownload
+ };
+
+ DownloadManager(QWidget *parent = 0);
+ ~DownloadManager();
+ int activeDownloads() const;
+
+ RemovePolicy removePolicy() const;
+ void setRemovePolicy(RemovePolicy policy);
+
+public slots:
+ void download(const QNetworkRequest &request, bool requestFileName = false);
+ inline void download(const QUrl &url, bool requestFileName = false)
+ { download(QNetworkRequest(url), requestFileName); }
+ void handleUnsupportedContent(QNetworkReply *reply, bool requestFileName = false);
+ void cleanup();
+
+private slots:
+ void save() const;
+ void updateRow();
+
+private:
+ void addItem(DownloadItem *item);
+ void updateItemCount();
+ void load();
+
+ AutoSaver *m_autoSaver;
+ DownloadModel *m_model;
+ QNetworkAccessManager *m_manager;
+ QFileIconProvider *m_iconProvider;
+ QList<DownloadItem*> m_downloads;
+ RemovePolicy m_removePolicy;
+ friend class DownloadModel;
+};
+
+class DownloadModel : public QAbstractListModel
+{
+ friend class DownloadManager;
+ Q_OBJECT
+
+public:
+ DownloadModel(DownloadManager *downloadManager, QObject *parent = 0);
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+
+private:
+ DownloadManager *m_downloadManager;
+
+};
+
+#endif // DOWNLOADMANAGER_H
+
diff --git a/demos/browser/downloads.ui b/demos/browser/downloads.ui
new file mode 100644
index 0000000..a2e2569
--- /dev/null
+++ b/demos/browser/downloads.ui
@@ -0,0 +1,83 @@
+<ui version="4.0" >
+ <class>DownloadDialog</class>
+ <widget class="QDialog" name="DownloadDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>332</width>
+ <height>252</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Downloads</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <item row="0" column="0" colspan="3" >
+ <widget class="EditTableView" name="downloadsView" />
+ </item>
+ <item row="1" column="0" >
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <widget class="QPushButton" name="cleanupButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Clean up</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>58</width>
+ <height>24</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLabel" name="itemCount" >
+ <property name="text" >
+ <string>0 Items</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <spacer name="horizontalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>148</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>EditTableView</class>
+ <extends>QTableView</extends>
+ <header>edittableview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/demos/browser/edittableview.cpp b/demos/browser/edittableview.cpp
new file mode 100644
index 0000000..0d776a7
--- /dev/null
+++ b/demos/browser/edittableview.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "edittableview.h"
+#include <QtGui/QKeyEvent>
+
+EditTableView::EditTableView(QWidget *parent)
+ : QTableView(parent)
+{
+}
+
+void EditTableView::keyPressEvent(QKeyEvent *event)
+{
+ if ((event->key() == Qt::Key_Delete
+ || event->key() == Qt::Key_Backspace)
+ && model()) {
+ removeOne();
+ } else {
+ QAbstractItemView::keyPressEvent(event);
+ }
+}
+
+void EditTableView::removeOne()
+{
+ if (!model() || !selectionModel())
+ return;
+ int row = currentIndex().row();
+ model()->removeRow(row, rootIndex());
+ QModelIndex idx = model()->index(row, 0, rootIndex());
+ if (!idx.isValid())
+ idx = model()->index(row - 1, 0, rootIndex());
+ selectionModel()->select(idx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
+}
+
+void EditTableView::removeAll()
+{
+ if (model())
+ model()->removeRows(0, model()->rowCount(rootIndex()), rootIndex());
+}
+
diff --git a/demos/browser/edittableview.h b/demos/browser/edittableview.h
new file mode 100644
index 0000000..3ae63e0
--- /dev/null
+++ b/demos/browser/edittableview.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef EDITTABLEVIEW_H
+#define EDITTABLEVIEW_H
+
+#include <QtGui/QTableView>
+
+class EditTableView : public QTableView
+{
+ Q_OBJECT
+
+public:
+ EditTableView(QWidget *parent = 0);
+ void keyPressEvent(QKeyEvent *event);
+
+public slots:
+ void removeOne();
+ void removeAll();
+};
+
+#endif // EDITTABLEVIEW_H
+
diff --git a/demos/browser/edittreeview.cpp b/demos/browser/edittreeview.cpp
new file mode 100644
index 0000000..0331ba7
--- /dev/null
+++ b/demos/browser/edittreeview.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "edittreeview.h"
+
+#include <QtGui/QKeyEvent>
+
+EditTreeView::EditTreeView(QWidget *parent)
+ : QTreeView(parent)
+{
+}
+
+void EditTreeView::keyPressEvent(QKeyEvent *event)
+{
+ if ((event->key() == Qt::Key_Delete
+ || event->key() == Qt::Key_Backspace)
+ && model()) {
+ removeOne();
+ } else {
+ QAbstractItemView::keyPressEvent(event);
+ }
+}
+
+void EditTreeView::removeOne()
+{
+ if (!model())
+ return;
+ QModelIndex ci = currentIndex();
+ int row = ci.row();
+ model()->removeRow(row, ci.parent());
+}
+
+void EditTreeView::removeAll()
+{
+ if (!model())
+ return;
+ model()->removeRows(0, model()->rowCount(rootIndex()), rootIndex());
+}
+
diff --git a/demos/browser/edittreeview.h b/demos/browser/edittreeview.h
new file mode 100644
index 0000000..97b9804
--- /dev/null
+++ b/demos/browser/edittreeview.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef EDITTREEVIEW_H
+#define EDITTREEVIEW_H
+
+#include <QtGui/QTreeView>
+
+class EditTreeView : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ EditTreeView(QWidget *parent = 0);
+ void keyPressEvent(QKeyEvent *event);
+
+public slots:
+ void removeOne();
+ void removeAll();
+};
+
+#endif // EDITTREEVIEW_H
+
diff --git a/demos/browser/history.cpp b/demos/browser/history.cpp
new file mode 100644
index 0000000..80e7372
--- /dev/null
+++ b/demos/browser/history.cpp
@@ -0,0 +1,1282 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "history.h"
+
+#include "autosaver.h"
+#include "browserapplication.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSettings>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QTextStream>
+
+#include <QtCore/QtAlgorithms>
+
+#include <QtGui/QClipboard>
+#include <QtGui/QDesktopServices>
+#include <QtGui/QHeaderView>
+#include <QtGui/QStyle>
+
+#include <QtWebKit/QWebHistoryInterface>
+#include <QtWebKit/QWebSettings>
+
+#include <QtCore/QDebug>
+
+static const unsigned int HISTORY_VERSION = 23;
+
+HistoryManager::HistoryManager(QObject *parent)
+ : QWebHistoryInterface(parent)
+ , m_saveTimer(new AutoSaver(this))
+ , m_historyLimit(30)
+ , m_historyModel(0)
+ , m_historyFilterModel(0)
+ , m_historyTreeModel(0)
+{
+ m_expiredTimer.setSingleShot(true);
+ connect(&m_expiredTimer, SIGNAL(timeout()),
+ this, SLOT(checkForExpired()));
+ connect(this, SIGNAL(entryAdded(const HistoryItem &)),
+ m_saveTimer, SLOT(changeOccurred()));
+ connect(this, SIGNAL(entryRemoved(const HistoryItem &)),
+ m_saveTimer, SLOT(changeOccurred()));
+ load();
+
+ m_historyModel = new HistoryModel(this, this);
+ m_historyFilterModel = new HistoryFilterModel(m_historyModel, this);
+ m_historyTreeModel = new HistoryTreeModel(m_historyFilterModel, this);
+
+ // QWebHistoryInterface will delete the history manager
+ QWebHistoryInterface::setDefaultInterface(this);
+}
+
+HistoryManager::~HistoryManager()
+{
+ m_saveTimer->saveIfNeccessary();
+}
+
+QList<HistoryItem> HistoryManager::history() const
+{
+ return m_history;
+}
+
+bool HistoryManager::historyContains(const QString &url) const
+{
+ return m_historyFilterModel->historyContains(url);
+}
+
+void HistoryManager::addHistoryEntry(const QString &url)
+{
+ QUrl cleanUrl(url);
+ cleanUrl.setPassword(QString());
+ cleanUrl.setHost(cleanUrl.host().toLower());
+ HistoryItem item(cleanUrl.toString(), QDateTime::currentDateTime());
+ addHistoryItem(item);
+}
+
+void HistoryManager::setHistory(const QList<HistoryItem> &history, bool loadedAndSorted)
+{
+ m_history = history;
+
+ // verify that it is sorted by date
+ if (!loadedAndSorted)
+ qSort(m_history.begin(), m_history.end());
+
+ checkForExpired();
+
+ if (loadedAndSorted) {
+ m_lastSavedUrl = m_history.value(0).url;
+ } else {
+ m_lastSavedUrl = QString();
+ m_saveTimer->changeOccurred();
+ }
+ emit historyReset();
+}
+
+HistoryModel *HistoryManager::historyModel() const
+{
+ return m_historyModel;
+}
+
+HistoryFilterModel *HistoryManager::historyFilterModel() const
+{
+ return m_historyFilterModel;
+}
+
+HistoryTreeModel *HistoryManager::historyTreeModel() const
+{
+ return m_historyTreeModel;
+}
+
+void HistoryManager::checkForExpired()
+{
+ if (m_historyLimit < 0 || m_history.isEmpty())
+ return;
+
+ QDateTime now = QDateTime::currentDateTime();
+ int nextTimeout = 0;
+
+ while (!m_history.isEmpty()) {
+ QDateTime checkForExpired = m_history.last().dateTime;
+ checkForExpired.setDate(checkForExpired.date().addDays(m_historyLimit));
+ if (now.daysTo(checkForExpired) > 7) {
+ // check at most in a week to prevent int overflows on the timer
+ nextTimeout = 7 * 86400;
+ } else {
+ nextTimeout = now.secsTo(checkForExpired);
+ }
+ if (nextTimeout > 0)
+ break;
+ HistoryItem item = m_history.takeLast();
+ // remove from saved file also
+ m_lastSavedUrl = QString();
+ emit entryRemoved(item);
+ }
+
+ if (nextTimeout > 0)
+ m_expiredTimer.start(nextTimeout * 1000);
+}
+
+void HistoryManager::addHistoryItem(const HistoryItem &item)
+{
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled))
+ return;
+
+ m_history.prepend(item);
+ emit entryAdded(item);
+ if (m_history.count() == 1)
+ checkForExpired();
+}
+
+void HistoryManager::updateHistoryItem(const QUrl &url, const QString &title)
+{
+ for (int i = 0; i < m_history.count(); ++i) {
+ if (url == m_history.at(i).url) {
+ m_history[i].title = title;
+ m_saveTimer->changeOccurred();
+ if (m_lastSavedUrl.isEmpty())
+ m_lastSavedUrl = m_history.at(i).url;
+ emit entryUpdated(i);
+ break;
+ }
+ }
+}
+
+int HistoryManager::historyLimit() const
+{
+ return m_historyLimit;
+}
+
+void HistoryManager::setHistoryLimit(int limit)
+{
+ if (m_historyLimit == limit)
+ return;
+ m_historyLimit = limit;
+ checkForExpired();
+ m_saveTimer->changeOccurred();
+}
+
+void HistoryManager::clear()
+{
+ m_history.clear();
+ m_lastSavedUrl = QString();
+ m_saveTimer->changeOccurred();
+ m_saveTimer->saveIfNeccessary();
+ historyReset();
+}
+
+void HistoryManager::loadSettings()
+{
+ // load settings
+ QSettings settings;
+ settings.beginGroup(QLatin1String("history"));
+ m_historyLimit = settings.value(QLatin1String("historyLimit"), 30).toInt();
+}
+
+void HistoryManager::load()
+{
+ loadSettings();
+
+ QFile historyFile(QDesktopServices::storageLocation(QDesktopServices::DataLocation)
+ + QLatin1String("/history"));
+ if (!historyFile.exists())
+ return;
+ if (!historyFile.open(QFile::ReadOnly)) {
+ qWarning() << "Unable to open history file" << historyFile.fileName();
+ return;
+ }
+
+ QList<HistoryItem> list;
+ QDataStream in(&historyFile);
+ // Double check that the history file is sorted as it is read in
+ bool needToSort = false;
+ HistoryItem lastInsertedItem;
+ QByteArray data;
+ QDataStream stream;
+ QBuffer buffer;
+ stream.setDevice(&buffer);
+ while (!historyFile.atEnd()) {
+ in >> data;
+ buffer.close();
+ buffer.setBuffer(&data);
+ buffer.open(QIODevice::ReadOnly);
+ quint32 ver;
+ stream >> ver;
+ if (ver != HISTORY_VERSION)
+ continue;
+ HistoryItem item;
+ stream >> item.url;
+ stream >> item.dateTime;
+ stream >> item.title;
+
+ if (!item.dateTime.isValid())
+ continue;
+
+ if (item == lastInsertedItem) {
+ if (lastInsertedItem.title.isEmpty() && !list.isEmpty())
+ list[0].title = item.title;
+ continue;
+ }
+
+ if (!needToSort && !list.isEmpty() && lastInsertedItem < item)
+ needToSort = true;
+
+ list.prepend(item);
+ lastInsertedItem = item;
+ }
+ if (needToSort)
+ qSort(list.begin(), list.end());
+
+ setHistory(list, true);
+
+ // If we had to sort re-write the whole history sorted
+ if (needToSort) {
+ m_lastSavedUrl = QString();
+ m_saveTimer->changeOccurred();
+ }
+}
+
+void HistoryManager::save()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("history"));
+ settings.setValue(QLatin1String("historyLimit"), m_historyLimit);
+
+ bool saveAll = m_lastSavedUrl.isEmpty();
+ int first = m_history.count() - 1;
+ if (!saveAll) {
+ // find the first one to save
+ for (int i = 0; i < m_history.count(); ++i) {
+ if (m_history.at(i).url == m_lastSavedUrl) {
+ first = i - 1;
+ break;
+ }
+ }
+ }
+ if (first == m_history.count() - 1)
+ saveAll = true;
+
+ QString directory = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
+ if (directory.isEmpty())
+ directory = QDir::homePath() + QLatin1String("/.") + QCoreApplication::applicationName();
+ if (!QFile::exists(directory)) {
+ QDir dir;
+ dir.mkpath(directory);
+ }
+
+ QFile historyFile(directory + QLatin1String("/history"));
+ // When saving everything use a temporary file to prevent possible data loss.
+ QTemporaryFile tempFile;
+ tempFile.setAutoRemove(false);
+ bool open = false;
+ if (saveAll) {
+ open = tempFile.open();
+ } else {
+ open = historyFile.open(QFile::Append);
+ }
+
+ if (!open) {
+ qWarning() << "Unable to open history file for saving"
+ << (saveAll ? tempFile.fileName() : historyFile.fileName());
+ return;
+ }
+
+ QDataStream out(saveAll ? &tempFile : &historyFile);
+ for (int i = first; i >= 0; --i) {
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+ HistoryItem item = m_history.at(i);
+ stream << HISTORY_VERSION << item.url << item.dateTime << item.title;
+ out << data;
+ }
+ tempFile.close();
+
+ if (saveAll) {
+ if (historyFile.exists() && !historyFile.remove())
+ qWarning() << "History: error removing old history." << historyFile.errorString();
+ if (!tempFile.rename(historyFile.fileName()))
+ qWarning() << "History: error moving new history over old." << tempFile.errorString() << historyFile.fileName();
+ }
+ m_lastSavedUrl = m_history.value(0).url;
+}
+
+HistoryModel::HistoryModel(HistoryManager *history, QObject *parent)
+ : QAbstractTableModel(parent)
+ , m_history(history)
+{
+ Q_ASSERT(m_history);
+ connect(m_history, SIGNAL(historyReset()),
+ this, SLOT(historyReset()));
+ connect(m_history, SIGNAL(entryRemoved(const HistoryItem &)),
+ this, SLOT(historyReset()));
+
+ connect(m_history, SIGNAL(entryAdded(const HistoryItem &)),
+ this, SLOT(entryAdded()));
+ connect(m_history, SIGNAL(entryUpdated(int)),
+ this, SLOT(entryUpdated(int)));
+}
+
+void HistoryModel::historyReset()
+{
+ reset();
+}
+
+void HistoryModel::entryAdded()
+{
+ beginInsertRows(QModelIndex(), 0, 0);
+ endInsertRows();
+}
+
+void HistoryModel::entryUpdated(int offset)
+{
+ QModelIndex idx = index(offset, 0);
+ emit dataChanged(idx, idx);
+}
+
+QVariant HistoryModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal
+ && role == Qt::DisplayRole) {
+ switch (section) {
+ case 0: return tr("Title");
+ case 1: return tr("Address");
+ }
+ }
+ return QAbstractTableModel::headerData(section, orientation, role);
+}
+
+QVariant HistoryModel::data(const QModelIndex &index, int role) const
+{
+ QList<HistoryItem> lst = m_history->history();
+ if (index.row() < 0 || index.row() >= lst.size())
+ return QVariant();
+
+ const HistoryItem &item = lst.at(index.row());
+ switch (role) {
+ case DateTimeRole:
+ return item.dateTime;
+ case DateRole:
+ return item.dateTime.date();
+ case UrlRole:
+ return QUrl(item.url);
+ case UrlStringRole:
+ return item.url;
+ case Qt::DisplayRole:
+ case Qt::EditRole: {
+ switch (index.column()) {
+ case 0:
+ // when there is no title try to generate one from the url
+ if (item.title.isEmpty()) {
+ QString page = QFileInfo(QUrl(item.url).path()).fileName();
+ if (!page.isEmpty())
+ return page;
+ return item.url;
+ }
+ return item.title;
+ case 1:
+ return item.url;
+ }
+ }
+ case Qt::DecorationRole:
+ if (index.column() == 0) {
+ return BrowserApplication::instance()->icon(item.url);
+ }
+ }
+ return QVariant();
+}
+
+int HistoryModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : 2;
+}
+
+int HistoryModel::rowCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : m_history->history().count();
+}
+
+bool HistoryModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (parent.isValid())
+ return false;
+ int lastRow = row + count - 1;
+ beginRemoveRows(parent, row, lastRow);
+ QList<HistoryItem> lst = m_history->history();
+ for (int i = lastRow; i >= row; --i)
+ lst.removeAt(i);
+ disconnect(m_history, SIGNAL(historyReset()), this, SLOT(historyReset()));
+ m_history->setHistory(lst);
+ connect(m_history, SIGNAL(historyReset()), this, SLOT(historyReset()));
+ endRemoveRows();
+ return true;
+}
+
+#define MOVEDROWS 15
+
+/*
+ Maps the first bunch of items of the source model to the root
+*/
+HistoryMenuModel::HistoryMenuModel(HistoryTreeModel *sourceModel, QObject *parent)
+ : QAbstractProxyModel(parent)
+ , m_treeModel(sourceModel)
+{
+ setSourceModel(sourceModel);
+}
+
+int HistoryMenuModel::bumpedRows() const
+{
+ QModelIndex first = m_treeModel->index(0, 0);
+ if (!first.isValid())
+ return 0;
+ return qMin(m_treeModel->rowCount(first), MOVEDROWS);
+}
+
+int HistoryMenuModel::columnCount(const QModelIndex &parent) const
+{
+ return m_treeModel->columnCount(mapToSource(parent));
+}
+
+int HistoryMenuModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.column() > 0)
+ return 0;
+
+ if (!parent.isValid()) {
+ int folders = sourceModel()->rowCount();
+ int bumpedItems = bumpedRows();
+ if (bumpedItems <= MOVEDROWS
+ && bumpedItems == sourceModel()->rowCount(sourceModel()->index(0, 0)))
+ --folders;
+ return bumpedItems + folders;
+ }
+
+ if (parent.internalId() == -1) {
+ if (parent.row() < bumpedRows())
+ return 0;
+ }
+
+ QModelIndex idx = mapToSource(parent);
+ int defaultCount = sourceModel()->rowCount(idx);
+ if (idx == sourceModel()->index(0, 0))
+ return defaultCount - bumpedRows();
+ return defaultCount;
+}
+
+QModelIndex HistoryMenuModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+ // currently not used or autotested
+ Q_ASSERT(false);
+ int sr = m_treeModel->mapToSource(sourceIndex).row();
+ return createIndex(sourceIndex.row(), sourceIndex.column(), sr);
+}
+
+QModelIndex HistoryMenuModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+ if (!proxyIndex.isValid())
+ return QModelIndex();
+
+ if (proxyIndex.internalId() == -1) {
+ int bumpedItems = bumpedRows();
+ if (proxyIndex.row() < bumpedItems)
+ return m_treeModel->index(proxyIndex.row(), proxyIndex.column(), m_treeModel->index(0, 0));
+ if (bumpedItems <= MOVEDROWS && bumpedItems == sourceModel()->rowCount(m_treeModel->index(0, 0)))
+ --bumpedItems;
+ return m_treeModel->index(proxyIndex.row() - bumpedItems, proxyIndex.column());
+ }
+
+ QModelIndex historyIndex = m_treeModel->sourceModel()->index(proxyIndex.internalId(), proxyIndex.column());
+ QModelIndex treeIndex = m_treeModel->mapFromSource(historyIndex);
+ return treeIndex;
+}
+
+QModelIndex HistoryMenuModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (row < 0
+ || column < 0 || column >= columnCount(parent)
+ || parent.column() > 0)
+ return QModelIndex();
+ if (!parent.isValid())
+ return createIndex(row, column, -1);
+
+ QModelIndex treeIndexParent = mapToSource(parent);
+
+ int bumpedItems = 0;
+ if (treeIndexParent == m_treeModel->index(0, 0))
+ bumpedItems = bumpedRows();
+ QModelIndex treeIndex = m_treeModel->index(row + bumpedItems, column, treeIndexParent);
+ QModelIndex historyIndex = m_treeModel->mapToSource(treeIndex);
+ int historyRow = historyIndex.row();
+ if (historyRow == -1)
+ historyRow = treeIndex.row();
+ return createIndex(row, column, historyRow);
+}
+
+QModelIndex HistoryMenuModel::parent(const QModelIndex &index) const
+{
+ int offset = index.internalId();
+ if (offset == -1 || !index.isValid())
+ return QModelIndex();
+
+ QModelIndex historyIndex = m_treeModel->sourceModel()->index(index.internalId(), 0);
+ QModelIndex treeIndex = m_treeModel->mapFromSource(historyIndex);
+ QModelIndex treeIndexParent = treeIndex.parent();
+
+ int sr = m_treeModel->mapToSource(treeIndexParent).row();
+ int bumpedItems = bumpedRows();
+ if (bumpedItems <= MOVEDROWS && bumpedItems == sourceModel()->rowCount(sourceModel()->index(0, 0)))
+ --bumpedItems;
+ return createIndex(bumpedItems + treeIndexParent.row(), treeIndexParent.column(), sr);
+}
+
+
+HistoryMenu::HistoryMenu(QWidget *parent)
+ : ModelMenu(parent)
+ , m_history(0)
+{
+ connect(this, SIGNAL(activated(const QModelIndex &)),
+ this, SLOT(activated(const QModelIndex &)));
+ setHoverRole(HistoryModel::UrlStringRole);
+}
+
+void HistoryMenu::activated(const QModelIndex &index)
+{
+ emit openUrl(index.data(HistoryModel::UrlRole).toUrl());
+}
+
+bool HistoryMenu::prePopulated()
+{
+ if (!m_history) {
+ m_history = BrowserApplication::historyManager();
+ m_historyMenuModel = new HistoryMenuModel(m_history->historyTreeModel(), this);
+ setModel(m_historyMenuModel);
+ }
+ // initial actions
+ for (int i = 0; i < m_initialActions.count(); ++i)
+ addAction(m_initialActions.at(i));
+ if (!m_initialActions.isEmpty())
+ addSeparator();
+ setFirstSeparator(m_historyMenuModel->bumpedRows());
+
+ return false;
+}
+
+void HistoryMenu::postPopulated()
+{
+ if (m_history->history().count() > 0)
+ addSeparator();
+
+ QAction *showAllAction = new QAction(tr("Show All History"), this);
+ connect(showAllAction, SIGNAL(triggered()), this, SLOT(showHistoryDialog()));
+ addAction(showAllAction);
+
+ QAction *clearAction = new QAction(tr("Clear History"), this);
+ connect(clearAction, SIGNAL(triggered()), m_history, SLOT(clear()));
+ addAction(clearAction);
+}
+
+void HistoryMenu::showHistoryDialog()
+{
+ HistoryDialog *dialog = new HistoryDialog(this);
+ connect(dialog, SIGNAL(openUrl(const QUrl&)),
+ this, SIGNAL(openUrl(const QUrl&)));
+ dialog->show();
+}
+
+void HistoryMenu::setInitialActions(QList<QAction*> actions)
+{
+ m_initialActions = actions;
+ for (int i = 0; i < m_initialActions.count(); ++i)
+ addAction(m_initialActions.at(i));
+}
+
+TreeProxyModel::TreeProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
+{
+ setSortRole(HistoryModel::DateTimeRole);
+ setFilterCaseSensitivity(Qt::CaseInsensitive);
+}
+
+bool TreeProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+ if (!source_parent.isValid())
+ return true;
+ return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
+}
+
+HistoryDialog::HistoryDialog(QWidget *parent, HistoryManager *setHistory) : QDialog(parent)
+{
+ HistoryManager *history = setHistory;
+ if (!history)
+ history = BrowserApplication::historyManager();
+ setupUi(this);
+ tree->setUniformRowHeights(true);
+ tree->setSelectionBehavior(QAbstractItemView::SelectRows);
+ tree->setTextElideMode(Qt::ElideMiddle);
+ QAbstractItemModel *model = history->historyTreeModel();
+ TreeProxyModel *proxyModel = new TreeProxyModel(this);
+ connect(search, SIGNAL(textChanged(QString)),
+ proxyModel, SLOT(setFilterFixedString(QString)));
+ connect(removeButton, SIGNAL(clicked()), tree, SLOT(removeOne()));
+ connect(removeAllButton, SIGNAL(clicked()), history, SLOT(clear()));
+ proxyModel->setSourceModel(model);
+ tree->setModel(proxyModel);
+ tree->setExpanded(proxyModel->index(0, 0), true);
+ tree->setAlternatingRowColors(true);
+ QFontMetrics fm(font());
+ int header = fm.width(QLatin1Char('m')) * 40;
+ tree->header()->resizeSection(0, header);
+ tree->header()->setStretchLastSection(true);
+ connect(tree, SIGNAL(activated(const QModelIndex&)),
+ this, SLOT(open()));
+ tree->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(tree, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(customContextMenuRequested(const QPoint &)));
+}
+
+void HistoryDialog::customContextMenuRequested(const QPoint &pos)
+{
+ QMenu menu;
+ QModelIndex index = tree->indexAt(pos);
+ index = index.sibling(index.row(), 0);
+ if (index.isValid() && !tree->model()->hasChildren(index)) {
+ menu.addAction(tr("Open"), this, SLOT(open()));
+ menu.addSeparator();
+ menu.addAction(tr("Copy"), this, SLOT(copy()));
+ }
+ menu.addAction(tr("Delete"), tree, SLOT(removeOne()));
+ menu.exec(QCursor::pos());
+}
+
+void HistoryDialog::open()
+{
+ QModelIndex index = tree->currentIndex();
+ if (!index.parent().isValid())
+ return;
+ emit openUrl(index.data(HistoryModel::UrlRole).toUrl());
+}
+
+void HistoryDialog::copy()
+{
+ QModelIndex index = tree->currentIndex();
+ if (!index.parent().isValid())
+ return;
+ QString url = index.data(HistoryModel::UrlStringRole).toString();
+
+ QClipboard *clipboard = QApplication::clipboard();
+ clipboard->setText(url);
+}
+
+HistoryFilterModel::HistoryFilterModel(QAbstractItemModel *sourceModel, QObject *parent)
+ : QAbstractProxyModel(parent),
+ m_loaded(false)
+{
+ setSourceModel(sourceModel);
+}
+
+int HistoryFilterModel::historyLocation(const QString &url) const
+{
+ load();
+ if (!m_historyHash.contains(url))
+ return 0;
+ return sourceModel()->rowCount() - m_historyHash.value(url);
+}
+
+QVariant HistoryFilterModel::data(const QModelIndex &index, int role) const
+{
+ return QAbstractProxyModel::data(index, role);
+}
+
+void HistoryFilterModel::setSourceModel(QAbstractItemModel *newSourceModel)
+{
+ if (sourceModel()) {
+ disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
+ disconnect(sourceModel(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
+ this, SLOT(dataChanged(const QModelIndex &, const QModelIndex &)));
+ disconnect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
+ this, SLOT(sourceRowsInserted(const QModelIndex &, int, int)));
+ disconnect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
+ this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int)));
+ }
+
+ QAbstractProxyModel::setSourceModel(newSourceModel);
+
+ if (sourceModel()) {
+ m_loaded = false;
+ connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
+ connect(sourceModel(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
+ this, SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &)));
+ connect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
+ this, SLOT(sourceRowsInserted(const QModelIndex &, int, int)));
+ connect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
+ this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int)));
+ }
+}
+
+void HistoryFilterModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+ emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight));
+}
+
+QVariant HistoryFilterModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ return sourceModel()->headerData(section, orientation, role);
+}
+
+void HistoryFilterModel::sourceReset()
+{
+ m_loaded = false;
+ reset();
+}
+
+int HistoryFilterModel::rowCount(const QModelIndex &parent) const
+{
+ load();
+ if (parent.isValid())
+ return 0;
+ return m_historyHash.count();
+}
+
+int HistoryFilterModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : 2;
+}
+
+QModelIndex HistoryFilterModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+ load();
+ int sourceRow = sourceModel()->rowCount() - proxyIndex.internalId();
+ return sourceModel()->index(sourceRow, proxyIndex.column());
+}
+
+QModelIndex HistoryFilterModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+ load();
+ QString url = sourceIndex.data(HistoryModel::UrlStringRole).toString();
+ if (!m_historyHash.contains(url))
+ return QModelIndex();
+
+ // This can be done in a binary search, but we can't use qBinary find
+ // because it can't take: qBinaryFind(m_sourceRow.end(), m_sourceRow.begin(), v);
+ // so if this is a performance bottlneck then convert to binary search, until then
+ // the cleaner/easier to read code wins the day.
+ int realRow = -1;
+ int sourceModelRow = sourceModel()->rowCount() - sourceIndex.row();
+
+ for (int i = 0; i < m_sourceRow.count(); ++i) {
+ if (m_sourceRow.at(i) == sourceModelRow) {
+ realRow = i;
+ break;
+ }
+ }
+ if (realRow == -1)
+ return QModelIndex();
+
+ return createIndex(realRow, sourceIndex.column(), sourceModel()->rowCount() - sourceIndex.row());
+}
+
+QModelIndex HistoryFilterModel::index(int row, int column, const QModelIndex &parent) const
+{
+ load();
+ if (row < 0 || row >= rowCount(parent)
+ || column < 0 || column >= columnCount(parent))
+ return QModelIndex();
+
+ return createIndex(row, column, m_sourceRow[row]);
+}
+
+QModelIndex HistoryFilterModel::parent(const QModelIndex &) const
+{
+ return QModelIndex();
+}
+
+void HistoryFilterModel::load() const
+{
+ if (m_loaded)
+ return;
+ m_sourceRow.clear();
+ m_historyHash.clear();
+ m_historyHash.reserve(sourceModel()->rowCount());
+ for (int i = 0; i < sourceModel()->rowCount(); ++i) {
+ QModelIndex idx = sourceModel()->index(i, 0);
+ QString url = idx.data(HistoryModel::UrlStringRole).toString();
+ if (!m_historyHash.contains(url)) {
+ m_sourceRow.append(sourceModel()->rowCount() - i);
+ m_historyHash[url] = sourceModel()->rowCount() - i;
+ }
+ }
+ m_loaded = true;
+}
+
+void HistoryFilterModel::sourceRowsInserted(const QModelIndex &parent, int start, int end)
+{
+ Q_ASSERT(start == end && start == 0);
+ Q_UNUSED(end);
+ if (!m_loaded)
+ return;
+ QModelIndex idx = sourceModel()->index(start, 0, parent);
+ QString url = idx.data(HistoryModel::UrlStringRole).toString();
+ if (m_historyHash.contains(url)) {
+ int sourceRow = sourceModel()->rowCount() - m_historyHash[url];
+ int realRow = mapFromSource(sourceModel()->index(sourceRow, 0)).row();
+ beginRemoveRows(QModelIndex(), realRow, realRow);
+ m_sourceRow.removeAt(realRow);
+ m_historyHash.remove(url);
+ endRemoveRows();
+ }
+ beginInsertRows(QModelIndex(), 0, 0);
+ m_historyHash.insert(url, sourceModel()->rowCount() - start);
+ m_sourceRow.insert(0, sourceModel()->rowCount());
+ endInsertRows();
+}
+
+void HistoryFilterModel::sourceRowsRemoved(const QModelIndex &, int start, int end)
+{
+ Q_UNUSED(start);
+ Q_UNUSED(end);
+ sourceReset();
+}
+
+/*
+ Removing a continuous block of rows will remove filtered rows too as this is
+ the users intention.
+*/
+bool HistoryFilterModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (row < 0 || count <= 0 || row + count > rowCount(parent) || parent.isValid())
+ return false;
+ int lastRow = row + count - 1;
+ disconnect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
+ this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int)));
+ beginRemoveRows(parent, row, lastRow);
+ int oldCount = rowCount();
+ int start = sourceModel()->rowCount() - m_sourceRow.value(row);
+ int end = sourceModel()->rowCount() - m_sourceRow.value(lastRow);
+ sourceModel()->removeRows(start, end - start + 1);
+ endRemoveRows();
+ connect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
+ this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int)));
+ m_loaded = false;
+ if (oldCount - count != rowCount())
+ reset();
+ return true;
+}
+
+HistoryCompletionModel::HistoryCompletionModel(QObject *parent)
+ : QAbstractProxyModel(parent)
+{
+}
+
+QVariant HistoryCompletionModel::data(const QModelIndex &index, int role) const
+{
+ if (sourceModel()
+ && (role == Qt::EditRole || role == Qt::DisplayRole)
+ && index.isValid()) {
+ QModelIndex idx = mapToSource(index);
+ idx = idx.sibling(idx.row(), 1);
+ QString urlString = idx.data(HistoryModel::UrlStringRole).toString();
+ if (index.row() % 2) {
+ QUrl url = urlString;
+ QString s = url.toString(QUrl::RemoveScheme
+ | QUrl::RemoveUserInfo
+ | QUrl::StripTrailingSlash);
+ return s.mid(2); // strip // from the front
+ }
+ return urlString;
+ }
+ return QAbstractProxyModel::data(index, role);
+}
+
+int HistoryCompletionModel::rowCount(const QModelIndex &parent) const
+{
+ return (parent.isValid() || !sourceModel()) ? 0 : sourceModel()->rowCount(parent) * 2;
+}
+
+int HistoryCompletionModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : 1;
+}
+
+QModelIndex HistoryCompletionModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+ int row = sourceIndex.row() * 2;
+ return index(row, sourceIndex.column());
+}
+
+QModelIndex HistoryCompletionModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+ if (!sourceModel())
+ return QModelIndex();
+ int row = proxyIndex.row() / 2;
+ return sourceModel()->index(row, proxyIndex.column());
+}
+
+QModelIndex HistoryCompletionModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (row < 0 || row >= rowCount(parent)
+ || column < 0 || column >= columnCount(parent))
+ return QModelIndex();
+ return createIndex(row, column, 0);
+}
+
+QModelIndex HistoryCompletionModel::parent(const QModelIndex &) const
+{
+ return QModelIndex();
+}
+
+void HistoryCompletionModel::setSourceModel(QAbstractItemModel *newSourceModel)
+{
+ if (sourceModel()) {
+ disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
+ disconnect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
+ this, SLOT(sourceReset()));
+ disconnect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
+ this, SLOT(sourceReset()));
+ }
+
+ QAbstractProxyModel::setSourceModel(newSourceModel);
+
+ if (newSourceModel) {
+ connect(newSourceModel, SIGNAL(modelReset()), this, SLOT(sourceReset()));
+ connect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
+ this, SLOT(sourceReset()));
+ connect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
+ this, SLOT(sourceReset()));
+ }
+
+ reset();
+}
+
+void HistoryCompletionModel::sourceReset()
+{
+ reset();
+}
+
+HistoryTreeModel::HistoryTreeModel(QAbstractItemModel *sourceModel, QObject *parent)
+ : QAbstractProxyModel(parent)
+{
+ setSourceModel(sourceModel);
+}
+
+QVariant HistoryTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ return sourceModel()->headerData(section, orientation, role);
+}
+
+QVariant HistoryTreeModel::data(const QModelIndex &index, int role) const
+{
+ if ((role == Qt::EditRole || role == Qt::DisplayRole)) {
+ int start = index.internalId();
+ if (start == 0) {
+ int offset = sourceDateRow(index.row());
+ if (index.column() == 0) {
+ QModelIndex idx = sourceModel()->index(offset, 0);
+ QDate date = idx.data(HistoryModel::DateRole).toDate();
+ if (date == QDate::currentDate())
+ return tr("Earlier Today");
+ return date.toString(QLatin1String("dddd, MMMM d, yyyy"));
+ }
+ if (index.column() == 1) {
+ return tr("%1 items").arg(rowCount(index.sibling(index.row(), 0)));
+ }
+ }
+ }
+ if (role == Qt::DecorationRole && index.column() == 0 && !index.parent().isValid())
+ return QIcon(QLatin1String(":history.png"));
+ if (role == HistoryModel::DateRole && index.column() == 0 && index.internalId() == 0) {
+ int offset = sourceDateRow(index.row());
+ QModelIndex idx = sourceModel()->index(offset, 0);
+ return idx.data(HistoryModel::DateRole);
+ }
+
+ return QAbstractProxyModel::data(index, role);
+}
+
+int HistoryTreeModel::columnCount(const QModelIndex &parent) const
+{
+ return sourceModel()->columnCount(mapToSource(parent));
+}
+
+int HistoryTreeModel::rowCount(const QModelIndex &parent) const
+{
+ if ( parent.internalId() != 0
+ || parent.column() > 0
+ || !sourceModel())
+ return 0;
+
+ // row count OF dates
+ if (!parent.isValid()) {
+ if (!m_sourceRowCache.isEmpty())
+ return m_sourceRowCache.count();
+ QDate currentDate;
+ int rows = 0;
+ int totalRows = sourceModel()->rowCount();
+
+ for (int i = 0; i < totalRows; ++i) {
+ QDate rowDate = sourceModel()->index(i, 0).data(HistoryModel::DateRole).toDate();
+ if (rowDate != currentDate) {
+ m_sourceRowCache.append(i);
+ currentDate = rowDate;
+ ++rows;
+ }
+ }
+ Q_ASSERT(m_sourceRowCache.count() == rows);
+ return rows;
+ }
+
+ // row count FOR a date
+ int start = sourceDateRow(parent.row());
+ int end = sourceDateRow(parent.row() + 1);
+ return (end - start);
+}
+
+// Translate the top level date row into the offset where that date starts
+int HistoryTreeModel::sourceDateRow(int row) const
+{
+ if (row <= 0)
+ return 0;
+
+ if (m_sourceRowCache.isEmpty())
+ rowCount(QModelIndex());
+
+ if (row >= m_sourceRowCache.count()) {
+ if (!sourceModel())
+ return 0;
+ return sourceModel()->rowCount();
+ }
+ return m_sourceRowCache.at(row);
+}
+
+QModelIndex HistoryTreeModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+ int offset = proxyIndex.internalId();
+ if (offset == 0)
+ return QModelIndex();
+ int startDateRow = sourceDateRow(offset - 1);
+ return sourceModel()->index(startDateRow + proxyIndex.row(), proxyIndex.column());
+}
+
+QModelIndex HistoryTreeModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (row < 0
+ || column < 0 || column >= columnCount(parent)
+ || parent.column() > 0)
+ return QModelIndex();
+
+ if (!parent.isValid())
+ return createIndex(row, column, 0);
+ return createIndex(row, column, parent.row() + 1);
+}
+
+QModelIndex HistoryTreeModel::parent(const QModelIndex &index) const
+{
+ int offset = index.internalId();
+ if (offset == 0 || !index.isValid())
+ return QModelIndex();
+ return createIndex(offset - 1, 0, 0);
+}
+
+bool HistoryTreeModel::hasChildren(const QModelIndex &parent) const
+{
+ QModelIndex grandparent = parent.parent();
+ if (!grandparent.isValid())
+ return true;
+ return false;
+}
+
+Qt::ItemFlags HistoryTreeModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
+}
+
+bool HistoryTreeModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (row < 0 || count <= 0 || row + count > rowCount(parent))
+ return false;
+
+ if (parent.isValid()) {
+ // removing pages
+ int offset = sourceDateRow(parent.row());
+ return sourceModel()->removeRows(offset + row, count);
+ } else {
+ // removing whole dates
+ for (int i = row + count - 1; i >= row; --i) {
+ QModelIndex dateParent = index(i, 0);
+ int offset = sourceDateRow(dateParent.row());
+ if (!sourceModel()->removeRows(offset, rowCount(dateParent)))
+ return false;
+ }
+ }
+ return true;
+}
+
+void HistoryTreeModel::setSourceModel(QAbstractItemModel *newSourceModel)
+{
+ if (sourceModel()) {
+ disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
+ disconnect(sourceModel(), SIGNAL(layoutChanged()), this, SLOT(sourceReset()));
+ disconnect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
+ this, SLOT(sourceRowsInserted(const QModelIndex &, int, int)));
+ disconnect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
+ this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int)));
+ }
+
+ QAbstractProxyModel::setSourceModel(newSourceModel);
+
+ if (newSourceModel) {
+ connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
+ connect(sourceModel(), SIGNAL(layoutChanged()), this, SLOT(sourceReset()));
+ connect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
+ this, SLOT(sourceRowsInserted(const QModelIndex &, int, int)));
+ connect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
+ this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int)));
+ }
+
+ reset();
+}
+
+void HistoryTreeModel::sourceReset()
+{
+ m_sourceRowCache.clear();
+ reset();
+}
+
+void HistoryTreeModel::sourceRowsInserted(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent); // Avoid warnings when compiling release
+ Q_ASSERT(!parent.isValid());
+ if (start != 0 || start != end) {
+ m_sourceRowCache.clear();
+ reset();
+ return;
+ }
+
+ m_sourceRowCache.clear();
+ QModelIndex treeIndex = mapFromSource(sourceModel()->index(start, 0));
+ QModelIndex treeParent = treeIndex.parent();
+ if (rowCount(treeParent) == 1) {
+ beginInsertRows(QModelIndex(), 0, 0);
+ endInsertRows();
+ } else {
+ beginInsertRows(treeParent, treeIndex.row(), treeIndex.row());
+ endInsertRows();
+ }
+}
+
+QModelIndex HistoryTreeModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+ if (!sourceIndex.isValid())
+ return QModelIndex();
+
+ if (m_sourceRowCache.isEmpty())
+ rowCount(QModelIndex());
+
+ QList<int>::iterator it;
+ it = qLowerBound(m_sourceRowCache.begin(), m_sourceRowCache.end(), sourceIndex.row());
+ if (*it != sourceIndex.row())
+ --it;
+ int dateRow = qMax(0, it - m_sourceRowCache.begin());
+ int row = sourceIndex.row() - m_sourceRowCache.at(dateRow);
+ return createIndex(row, sourceIndex.column(), dateRow + 1);
+}
+
+void HistoryTreeModel::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent); // Avoid warnings when compiling release
+ Q_ASSERT(!parent.isValid());
+ if (m_sourceRowCache.isEmpty())
+ return;
+ for (int i = end; i >= start;) {
+ QList<int>::iterator it;
+ it = qLowerBound(m_sourceRowCache.begin(), m_sourceRowCache.end(), i);
+ // playing it safe
+ if (it == m_sourceRowCache.end()) {
+ m_sourceRowCache.clear();
+ reset();
+ return;
+ }
+
+ if (*it != i)
+ --it;
+ int row = qMax(0, it - m_sourceRowCache.begin());
+ int offset = m_sourceRowCache[row];
+ QModelIndex dateParent = index(row, 0);
+ // If we can remove all the rows in the date do that and skip over them
+ int rc = rowCount(dateParent);
+ if (i - rc + 1 == offset && start <= i - rc + 1) {
+ beginRemoveRows(QModelIndex(), row, row);
+ m_sourceRowCache.removeAt(row);
+ i -= rc + 1;
+ } else {
+ beginRemoveRows(dateParent, i - offset, i - offset);
+ ++row;
+ --i;
+ }
+ for (int j = row; j < m_sourceRowCache.count(); ++j)
+ --m_sourceRowCache[j];
+ endRemoveRows();
+ }
+}
+
diff --git a/demos/browser/history.h b/demos/browser/history.h
new file mode 100644
index 0000000..4f4edcd
--- /dev/null
+++ b/demos/browser/history.h
@@ -0,0 +1,350 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HISTORY_H
+#define HISTORY_H
+
+#include "modelmenu.h"
+
+#include <QtCore/QDateTime>
+#include <QtCore/QHash>
+#include <QtCore/QObject>
+#include <QtCore/QTimer>
+#include <QtCore/QUrl>
+
+#include <QtGui/QSortFilterProxyModel>
+
+#include <QWebHistoryInterface>
+
+class HistoryItem
+{
+public:
+ HistoryItem() {}
+ HistoryItem(const QString &u,
+ const QDateTime &d = QDateTime(), const QString &t = QString())
+ : title(t), url(u), dateTime(d) {}
+
+ inline bool operator==(const HistoryItem &other) const
+ { return other.title == title
+ && other.url == url && other.dateTime == dateTime; }
+
+ // history is sorted in reverse
+ inline bool operator <(const HistoryItem &other) const
+ { return dateTime > other.dateTime; }
+
+ QString title;
+ QString url;
+ QDateTime dateTime;
+};
+
+class AutoSaver;
+class HistoryModel;
+class HistoryFilterModel;
+class HistoryTreeModel;
+class HistoryManager : public QWebHistoryInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(int historyLimit READ historyLimit WRITE setHistoryLimit)
+
+signals:
+ void historyReset();
+ void entryAdded(const HistoryItem &item);
+ void entryRemoved(const HistoryItem &item);
+ void entryUpdated(int offset);
+
+public:
+ HistoryManager(QObject *parent = 0);
+ ~HistoryManager();
+
+ bool historyContains(const QString &url) const;
+ void addHistoryEntry(const QString &url);
+
+ void updateHistoryItem(const QUrl &url, const QString &title);
+
+ int historyLimit() const;
+ void setHistoryLimit(int limit);
+
+ QList<HistoryItem> history() const;
+ void setHistory(const QList<HistoryItem> &history, bool loadedAndSorted = false);
+
+ // History manager keeps around these models for use by the completer and other classes
+ HistoryModel *historyModel() const;
+ HistoryFilterModel *historyFilterModel() const;
+ HistoryTreeModel *historyTreeModel() const;
+
+public slots:
+ void clear();
+ void loadSettings();
+
+private slots:
+ void save();
+ void checkForExpired();
+
+protected:
+ void addHistoryItem(const HistoryItem &item);
+
+private:
+ void load();
+
+ AutoSaver *m_saveTimer;
+ int m_historyLimit;
+ QTimer m_expiredTimer;
+ QList<HistoryItem> m_history;
+ QString m_lastSavedUrl;
+
+ HistoryModel *m_historyModel;
+ HistoryFilterModel *m_historyFilterModel;
+ HistoryTreeModel *m_historyTreeModel;
+};
+
+class HistoryModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public slots:
+ void historyReset();
+ void entryAdded();
+ void entryUpdated(int offset);
+
+public:
+ enum Roles {
+ DateRole = Qt::UserRole + 1,
+ DateTimeRole = Qt::UserRole + 2,
+ UrlRole = Qt::UserRole + 3,
+ UrlStringRole = Qt::UserRole + 4
+ };
+
+ HistoryModel(HistoryManager *history, QObject *parent = 0);
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+
+private:
+ HistoryManager *m_history;
+};
+
+/*!
+ Proxy model that will remove any duplicate entries.
+ Both m_sourceRow and m_historyHash store their offsets not from
+ the front of the list, but as offsets from the back.
+ */
+class HistoryFilterModel : public QAbstractProxyModel
+{
+ Q_OBJECT
+
+public:
+ HistoryFilterModel(QAbstractItemModel *sourceModel, QObject *parent = 0);
+
+ inline bool historyContains(const QString &url) const
+ { load(); return m_historyHash.contains(url); }
+ int historyLocation(const QString &url) const;
+
+ QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
+ QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
+ void setSourceModel(QAbstractItemModel *sourceModel);
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex index(int, int, const QModelIndex& = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex& index= QModelIndex()) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+private slots:
+ void sourceReset();
+ void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ void sourceRowsInserted(const QModelIndex &parent, int start, int end);
+ void sourceRowsRemoved(const QModelIndex &, int, int);
+
+private:
+ void load() const;
+
+ mutable QList<int> m_sourceRow;
+ mutable QHash<QString, int> m_historyHash;
+ mutable bool m_loaded;
+};
+
+/*
+ The history menu
+ - Removes the first twenty entries and puts them as children of the top level.
+ - If there are less then twenty entries then the first folder is also removed.
+
+ The mapping is done by knowing that HistoryTreeModel is over a table
+ We store that row offset in our index's private data.
+*/
+class HistoryMenuModel : public QAbstractProxyModel
+{
+ Q_OBJECT
+
+public:
+ HistoryMenuModel(HistoryTreeModel *sourceModel, QObject *parent = 0);
+ int columnCount(const QModelIndex &parent) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex mapFromSource(const QModelIndex & sourceIndex) const;
+ QModelIndex mapToSource(const QModelIndex & proxyIndex) const;
+ QModelIndex index(int, int, const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &index = QModelIndex()) const;
+
+ int bumpedRows() const;
+
+private:
+ HistoryTreeModel *m_treeModel;
+};
+
+// Menu that is dynamically populated from the history
+class HistoryMenu : public ModelMenu
+{
+ Q_OBJECT
+
+signals:
+ void openUrl(const QUrl &url);
+
+public:
+ HistoryMenu(QWidget *parent = 0);
+ void setInitialActions(QList<QAction*> actions);
+
+protected:
+ bool prePopulated();
+ void postPopulated();
+
+private slots:
+ void activated(const QModelIndex &index);
+ void showHistoryDialog();
+
+private:
+ HistoryManager *m_history;
+ HistoryMenuModel *m_historyMenuModel;
+ QList<QAction*> m_initialActions;
+};
+
+// proxy model for the history model that
+// exposes each url http://www.foo.com and it url starting at the host www.foo.com
+class HistoryCompletionModel : public QAbstractProxyModel
+{
+ Q_OBJECT
+
+public:
+ HistoryCompletionModel(QObject *parent = 0);
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
+ QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
+ QModelIndex index(int, int, const QModelIndex& = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex& index= QModelIndex()) const;
+ void setSourceModel(QAbstractItemModel *sourceModel);
+
+private slots:
+ void sourceReset();
+
+};
+
+// proxy model for the history model that converts the list
+// into a tree, one top level node per day.
+// Used in the HistoryDialog.
+class HistoryTreeModel : public QAbstractProxyModel
+{
+ Q_OBJECT
+
+public:
+ HistoryTreeModel(QAbstractItemModel *sourceModel, QObject *parent = 0);
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int columnCount(const QModelIndex &parent) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
+ QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &index= QModelIndex()) const;
+ bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+
+ void setSourceModel(QAbstractItemModel *sourceModel);
+
+private slots:
+ void sourceReset();
+ void sourceRowsInserted(const QModelIndex &parent, int start, int end);
+ void sourceRowsRemoved(const QModelIndex &parent, int start, int end);
+
+private:
+ int sourceDateRow(int row) const;
+ mutable QList<int> m_sourceRowCache;
+
+};
+
+// A modified QSortFilterProxyModel that always accepts the root nodes in the tree
+// so filtering is only done on the children.
+// Used in the HistoryDialog
+class TreeProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+public:
+ TreeProxyModel(QObject *parent = 0);
+
+protected:
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
+};
+
+#include "ui_history.h"
+
+class HistoryDialog : public QDialog, public Ui_HistoryDialog
+{
+ Q_OBJECT
+
+signals:
+ void openUrl(const QUrl &url);
+
+public:
+ HistoryDialog(QWidget *parent = 0, HistoryManager *history = 0);
+
+private slots:
+ void customContextMenuRequested(const QPoint &pos);
+ void open();
+ void copy();
+
+};
+
+#endif // HISTORY_H
+
diff --git a/demos/browser/history.ui b/demos/browser/history.ui
new file mode 100644
index 0000000..0944940
--- /dev/null
+++ b/demos/browser/history.ui
@@ -0,0 +1,106 @@
+<ui version="4.0" >
+ <class>HistoryDialog</class>
+ <widget class="QDialog" name="HistoryDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>758</width>
+ <height>450</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>History</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>252</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1" >
+ <widget class="SearchLineEdit" name="search" />
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="EditTreeView" name="tree" />
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QPushButton" name="removeButton" >
+ <property name="text" >
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeAllButton" >
+ <property name="text" >
+ <string>Remove &amp;All</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>SearchLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>searchlineedit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>EditTreeView</class>
+ <extends>QTreeView</extends>
+ <header>edittreeview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>HistoryDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>472</x>
+ <y>329</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>461</x>
+ <y>356</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/demos/browser/htmls/htmls.qrc b/demos/browser/htmls/htmls.qrc
new file mode 100644
index 0000000..03b256c
--- /dev/null
+++ b/demos/browser/htmls/htmls.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>notfound.html</file>
+</qresource>
+</RCC>
diff --git a/demos/browser/htmls/notfound.html b/demos/browser/htmls/notfound.html
new file mode 100644
index 0000000..b04a9f8
--- /dev/null
+++ b/demos/browser/htmls/notfound.html
@@ -0,0 +1,63 @@
+<html>
+<head>
+<title>%1</title>
+<style>
+body {
+ padding: 3em 0em;
+ background: #eeeeee;
+}
+hr {
+ color: lightgray;
+ width: 100%;
+}
+img {
+ float: left;
+ opacity: .8;
+}
+#box {
+ background: white;
+ border: 1px solid lightgray;
+ width: 600px;
+ padding: 60px;
+ margin: auto;
+}
+h1 {
+ font-size: 130%;
+ font-weight: bold;
+ border-bottom: 1px solid lightgray;
+ margin-left: 48px;
+}
+h2 {
+ font-size: 100%;
+ font-weight: normal;
+ border-bottom: 1px solid lightgray;
+ margin-left: 48px;
+}
+ul {
+ font-size: 80%;
+ padding-left: 48px;
+ margin: 0;
+}
+#reloadButton {
+ padding-left: 48px;
+}
+</style>
+</head>
+<body>
+ <div id="box">
+ <img src="data:image/png;base64,IMAGE_BINARY_DATA_HERE" width="32" height="32"/>
+ <h1>%2</h1>
+ <h2>When connecting to: %3.</h2>
+ <ul>
+ <li>Check the address for errors such as <b>ww</b>.trolltech.com
+ instead of <b>www</b>.trolltech.com</li>
+ <li>If the address is correct, try checking the network
+ connection.</li>
+ <li>If your computer or network is protected by a firewall or
+ proxy, make sure that the browser demo is permitted to access
+ the network.</li>
+ </ul>
+ <br/><br/>
+ </div>
+</body>
+</html>
diff --git a/demos/browser/main.cpp b/demos/browser/main.cpp
new file mode 100644
index 0000000..a59b2fb
--- /dev/null
+++ b/demos/browser/main.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "browserapplication.h"
+
+int main(int argc, char **argv)
+{
+ Q_INIT_RESOURCE(data);
+ BrowserApplication application(argc, argv);
+ if (!application.isTheOnlyBrowser())
+ return 0;
+ application.newMainWindow();
+ return application.exec();
+}
+
diff --git a/demos/browser/modelmenu.cpp b/demos/browser/modelmenu.cpp
new file mode 100644
index 0000000..9403ef1
--- /dev/null
+++ b/demos/browser/modelmenu.cpp
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "modelmenu.h"
+
+#include <QtCore/QAbstractItemModel>
+#include <qdebug.h>
+
+ModelMenu::ModelMenu(QWidget * parent)
+ : QMenu(parent)
+ , m_maxRows(7)
+ , m_firstSeparator(-1)
+ , m_maxWidth(-1)
+ , m_hoverRole(0)
+ , m_separatorRole(0)
+ , m_model(0)
+{
+ connect(this, SIGNAL(aboutToShow()), this, SLOT(aboutToShow()));
+}
+
+bool ModelMenu::prePopulated()
+{
+ return false;
+}
+
+void ModelMenu::postPopulated()
+{
+}
+
+void ModelMenu::setModel(QAbstractItemModel *model)
+{
+ m_model = model;
+}
+
+QAbstractItemModel *ModelMenu::model() const
+{
+ return m_model;
+}
+
+void ModelMenu::setMaxRows(int max)
+{
+ m_maxRows = max;
+}
+
+int ModelMenu::maxRows() const
+{
+ return m_maxRows;
+}
+
+void ModelMenu::setFirstSeparator(int offset)
+{
+ m_firstSeparator = offset;
+}
+
+int ModelMenu::firstSeparator() const
+{
+ return m_firstSeparator;
+}
+
+void ModelMenu::setRootIndex(const QModelIndex &index)
+{
+ m_root = index;
+}
+
+QModelIndex ModelMenu::rootIndex() const
+{
+ return m_root;
+}
+
+void ModelMenu::setHoverRole(int role)
+{
+ m_hoverRole = role;
+}
+
+int ModelMenu::hoverRole() const
+{
+ return m_hoverRole;
+}
+
+void ModelMenu::setSeparatorRole(int role)
+{
+ m_separatorRole = role;
+}
+
+int ModelMenu::separatorRole() const
+{
+ return m_separatorRole;
+}
+
+Q_DECLARE_METATYPE(QModelIndex)
+void ModelMenu::aboutToShow()
+{
+ if (QMenu *menu = qobject_cast<QMenu*>(sender())) {
+ QVariant v = menu->menuAction()->data();
+ if (v.canConvert<QModelIndex>()) {
+ QModelIndex idx = qvariant_cast<QModelIndex>(v);
+ createMenu(idx, -1, menu, menu);
+ disconnect(menu, SIGNAL(aboutToShow()), this, SLOT(aboutToShow()));
+ return;
+ }
+ }
+
+ clear();
+ if (prePopulated())
+ addSeparator();
+ int max = m_maxRows;
+ if (max != -1)
+ max += m_firstSeparator;
+ createMenu(m_root, max, this, this);
+ postPopulated();
+}
+
+void ModelMenu::createMenu(const QModelIndex &parent, int max, QMenu *parentMenu, QMenu *menu)
+{
+ if (!menu) {
+ QString title = parent.data().toString();
+ menu = new QMenu(title, this);
+ QIcon icon = qvariant_cast<QIcon>(parent.data(Qt::DecorationRole));
+ menu->setIcon(icon);
+ parentMenu->addMenu(menu);
+ QVariant v;
+ v.setValue(parent);
+ menu->menuAction()->setData(v);
+ connect(menu, SIGNAL(aboutToShow()), this, SLOT(aboutToShow()));
+ return;
+ }
+
+ int end = m_model->rowCount(parent);
+ if (max != -1)
+ end = qMin(max, end);
+
+ connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(triggered(QAction*)));
+ connect(menu, SIGNAL(hovered(QAction*)), this, SLOT(hovered(QAction*)));
+
+ for (int i = 0; i < end; ++i) {
+ QModelIndex idx = m_model->index(i, 0, parent);
+ if (m_model->hasChildren(idx)) {
+ createMenu(idx, -1, menu);
+ } else {
+ if (m_separatorRole != 0
+ && idx.data(m_separatorRole).toBool())
+ addSeparator();
+ else
+ menu->addAction(makeAction(idx));
+ }
+ if (menu == this && i == m_firstSeparator - 1)
+ addSeparator();
+ }
+}
+
+QAction *ModelMenu::makeAction(const QModelIndex &index)
+{
+ QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
+ QAction *action = makeAction(icon, index.data().toString(), this);
+ QVariant v;
+ v.setValue(index);
+ action->setData(v);
+ return action;
+}
+
+QAction *ModelMenu::makeAction(const QIcon &icon, const QString &text, QObject *parent)
+{
+ QFontMetrics fm(font());
+ if (-1 == m_maxWidth)
+ m_maxWidth = fm.width(QLatin1Char('m')) * 30;
+ QString smallText = fm.elidedText(text, Qt::ElideMiddle, m_maxWidth);
+ return new QAction(icon, smallText, parent);
+}
+
+void ModelMenu::triggered(QAction *action)
+{
+ QVariant v = action->data();
+ if (v.canConvert<QModelIndex>()) {
+ QModelIndex idx = qvariant_cast<QModelIndex>(v);
+ emit activated(idx);
+ }
+}
+
+void ModelMenu::hovered(QAction *action)
+{
+ QVariant v = action->data();
+ if (v.canConvert<QModelIndex>()) {
+ QModelIndex idx = qvariant_cast<QModelIndex>(v);
+ QString hoveredString = idx.data(m_hoverRole).toString();
+ if (!hoveredString.isEmpty())
+ emit hovered(hoveredString);
+ }
+}
+
diff --git a/demos/browser/modelmenu.h b/demos/browser/modelmenu.h
new file mode 100644
index 0000000..edd2e04
--- /dev/null
+++ b/demos/browser/modelmenu.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MODELMENU_H
+#define MODELMENU_H
+
+#include <QtGui/QMenu>
+#include <QtCore/QAbstractItemModel>
+
+// A QMenu that is dynamically populated from a QAbstractItemModel
+class ModelMenu : public QMenu
+{
+ Q_OBJECT
+
+signals:
+ void activated(const QModelIndex &index);
+ void hovered(const QString &text);
+
+public:
+ ModelMenu(QWidget *parent = 0);
+
+ void setModel(QAbstractItemModel *model);
+ QAbstractItemModel *model() const;
+
+ void setMaxRows(int max);
+ int maxRows() const;
+
+ void setFirstSeparator(int offset);
+ int firstSeparator() const;
+
+ void setRootIndex(const QModelIndex &index);
+ QModelIndex rootIndex() const;
+
+ void setHoverRole(int role);
+ int hoverRole() const;
+
+ void setSeparatorRole(int role);
+ int separatorRole() const;
+
+ QAction *makeAction(const QIcon &icon, const QString &text, QObject *parent);
+
+protected:
+ // add any actions before the tree, return true if any actions are added.
+ virtual bool prePopulated();
+ // add any actions after the tree
+ virtual void postPopulated();
+ // put all of the children of parent into menu up to max
+ void createMenu(const QModelIndex &parent, int max, QMenu *parentMenu = 0, QMenu *menu = 0);
+
+private slots:
+ void aboutToShow();
+ void triggered(QAction *action);
+ void hovered(QAction *action);
+
+private:
+ QAction *makeAction(const QModelIndex &index);
+ int m_maxRows;
+ int m_firstSeparator;
+ int m_maxWidth;
+ int m_hoverRole;
+ int m_separatorRole;
+ QAbstractItemModel *m_model;
+ QPersistentModelIndex m_root;
+};
+
+#endif // MODELMENU_H
+
diff --git a/demos/browser/networkaccessmanager.cpp b/demos/browser/networkaccessmanager.cpp
new file mode 100644
index 0000000..2e7b2fd
--- /dev/null
+++ b/demos/browser/networkaccessmanager.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "networkaccessmanager.h"
+
+#include "browserapplication.h"
+#include "browsermainwindow.h"
+#include "ui_passworddialog.h"
+#include "ui_proxy.h"
+
+#include <QtCore/QSettings>
+
+#include <QtGui/QDesktopServices>
+#include <QtGui/QDialog>
+#include <QtGui/QMessageBox>
+#include <QtGui/QStyle>
+#include <QtGui/QTextDocument>
+
+#include <QtNetwork/QAuthenticator>
+#include <QtNetwork/QNetworkDiskCache>
+#include <QtNetwork/QNetworkProxy>
+#include <QtNetwork/QNetworkReply>
+#include <QtNetwork/QSslError>
+
+NetworkAccessManager::NetworkAccessManager(QObject *parent)
+ : QNetworkAccessManager(parent)
+{
+ connect(this, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),
+ SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
+ connect(this, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
+ SLOT(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)));
+#ifndef QT_NO_OPENSSL
+ connect(this, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)),
+ SLOT(sslErrors(QNetworkReply*, const QList<QSslError>&)));
+#endif
+ loadSettings();
+
+ QNetworkDiskCache *diskCache = new QNetworkDiskCache(this);
+ QString location = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);
+ diskCache->setCacheDirectory(location);
+ setCache(diskCache);
+}
+
+void NetworkAccessManager::loadSettings()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("proxy"));
+ QNetworkProxy proxy;
+ if (settings.value(QLatin1String("enabled"), false).toBool()) {
+ if (settings.value(QLatin1String("type"), 0).toInt() == 0)
+ proxy = QNetworkProxy::Socks5Proxy;
+ else
+ proxy = QNetworkProxy::HttpProxy;
+ proxy.setHostName(settings.value(QLatin1String("hostName")).toString());
+ proxy.setPort(settings.value(QLatin1String("port"), 1080).toInt());
+ proxy.setUser(settings.value(QLatin1String("userName")).toString());
+ proxy.setPassword(settings.value(QLatin1String("password")).toString());
+ }
+ setProxy(proxy);
+}
+
+void NetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *auth)
+{
+ BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow();
+
+ QDialog dialog(mainWindow);
+ dialog.setWindowFlags(Qt::Sheet);
+
+ Ui::PasswordDialog passwordDialog;
+ passwordDialog.setupUi(&dialog);
+
+ passwordDialog.iconLabel->setText(QString());
+ passwordDialog.iconLabel->setPixmap(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mainWindow).pixmap(32, 32));
+
+ QString introMessage = tr("<qt>Enter username and password for \"%1\" at %2</qt>");
+ introMessage = introMessage.arg(Qt::escape(reply->url().toString())).arg(Qt::escape(reply->url().toString()));
+ passwordDialog.introLabel->setText(introMessage);
+ passwordDialog.introLabel->setWordWrap(true);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ auth->setUser(passwordDialog.userNameLineEdit->text());
+ auth->setPassword(passwordDialog.passwordLineEdit->text());
+ }
+}
+
+void NetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth)
+{
+ BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow();
+
+ QDialog dialog(mainWindow);
+ dialog.setWindowFlags(Qt::Sheet);
+
+ Ui::ProxyDialog proxyDialog;
+ proxyDialog.setupUi(&dialog);
+
+ proxyDialog.iconLabel->setText(QString());
+ proxyDialog.iconLabel->setPixmap(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mainWindow).pixmap(32, 32));
+
+ QString introMessage = tr("<qt>Connect to proxy \"%1\" using:</qt>");
+ introMessage = introMessage.arg(Qt::escape(proxy.hostName()));
+ proxyDialog.introLabel->setText(introMessage);
+ proxyDialog.introLabel->setWordWrap(true);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ auth->setUser(proxyDialog.userNameLineEdit->text());
+ auth->setPassword(proxyDialog.passwordLineEdit->text());
+ }
+}
+
+#ifndef QT_NO_OPENSSL
+void NetworkAccessManager::sslErrors(QNetworkReply *reply, const QList<QSslError> &error)
+{
+ // check if SSL certificate has been trusted already
+ QString replyHost = reply->url().host() + ":" + reply->url().port();
+ if(! sslTrustedHostList.contains(replyHost)) {
+ BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow();
+
+ QStringList errorStrings;
+ for (int i = 0; i < error.count(); ++i)
+ errorStrings += error.at(i).errorString();
+ QString errors = errorStrings.join(QLatin1String("\n"));
+ int ret = QMessageBox::warning(mainWindow, QCoreApplication::applicationName(),
+ tr("SSL Errors:\n\n%1\n\n%2\n\n"
+ "Do you want to ignore these errors for this host?").arg(reply->url().toString()).arg(errors),
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::No);
+ if (ret == QMessageBox::Yes) {
+ reply->ignoreSslErrors();
+ sslTrustedHostList.append(replyHost);
+ }
+ }
+}
+#endif
diff --git a/demos/browser/networkaccessmanager.h b/demos/browser/networkaccessmanager.h
new file mode 100644
index 0000000..d016e76
--- /dev/null
+++ b/demos/browser/networkaccessmanager.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NETWORKACCESSMANAGER_H
+#define NETWORKACCESSMANAGER_H
+
+#include <QtNetwork/QNetworkAccessManager>
+
+class NetworkAccessManager : public QNetworkAccessManager
+{
+ Q_OBJECT
+
+public:
+ NetworkAccessManager(QObject *parent = 0);
+
+private:
+ QList<QString> sslTrustedHostList;
+
+public slots:
+ void loadSettings();
+
+private slots:
+ void authenticationRequired(QNetworkReply *reply, QAuthenticator *auth);
+ void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth);
+#ifndef QT_NO_OPENSSL
+ void sslErrors(QNetworkReply *reply, const QList<QSslError> &error);
+#endif
+};
+
+#endif // NETWORKACCESSMANAGER_H
diff --git a/demos/browser/passworddialog.ui b/demos/browser/passworddialog.ui
new file mode 100644
index 0000000..7c16658
--- /dev/null
+++ b/demos/browser/passworddialog.ui
@@ -0,0 +1,111 @@
+<ui version="4.0" >
+ <class>PasswordDialog</class>
+ <widget class="QDialog" name="PasswordDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>399</width>
+ <height>148</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Authentication Required</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" colspan="2" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="iconLabel" >
+ <property name="text" >
+ <string>DUMMY ICON</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="introLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>INTRO TEXT DUMMY</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Username:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="userNameLineEdit" />
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="lblPassword" >
+ <property name="text" >
+ <string>Password:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLineEdit" name="passwordLineEdit" >
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>PasswordDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>PasswordDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/demos/browser/proxy.ui b/demos/browser/proxy.ui
new file mode 100644
index 0000000..62a8be6
--- /dev/null
+++ b/demos/browser/proxy.ui
@@ -0,0 +1,104 @@
+<ui version="4.0" >
+ <class>ProxyDialog</class>
+ <widget class="QDialog" name="ProxyDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>369</width>
+ <height>144</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Proxy Authentication</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="iconLabel" >
+ <property name="text" >
+ <string>ICON</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2" >
+ <widget class="QLabel" name="introLabel" >
+ <property name="text" >
+ <string>Connect to proxy</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="QLabel" name="usernameLabel" >
+ <property name="text" >
+ <string>Username:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QLineEdit" name="userNameLineEdit" />
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <widget class="QLabel" name="passwordLabel" >
+ <property name="text" >
+ <string>Password:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" >
+ <widget class="QLineEdit" name="passwordLineEdit" >
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="3" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ProxyDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ProxyDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/demos/browser/searchlineedit.cpp b/demos/browser/searchlineedit.cpp
new file mode 100644
index 0000000..8f668e0
--- /dev/null
+++ b/demos/browser/searchlineedit.cpp
@@ -0,0 +1,238 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "searchlineedit.h"
+
+#include <QtGui/QPainter>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QStyle>
+#include <QtGui/QStyleOptionFrameV2>
+
+ClearButton::ClearButton(QWidget *parent)
+ : QAbstractButton(parent)
+{
+ setCursor(Qt::ArrowCursor);
+ setToolTip(tr("Clear"));
+ setVisible(false);
+ setFocusPolicy(Qt::NoFocus);
+}
+
+void ClearButton::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+ QPainter painter(this);
+ int height = this->height();
+
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ QColor color = palette().color(QPalette::Mid);
+ painter.setBrush(isDown()
+ ? palette().color(QPalette::Dark)
+ : palette().color(QPalette::Mid));
+ painter.setPen(painter.brush().color());
+ int size = width();
+ int offset = size / 5;
+ int radius = size - offset * 2;
+ painter.drawEllipse(offset, offset, radius, radius);
+
+ painter.setPen(palette().color(QPalette::Base));
+ int border = offset * 2;
+ painter.drawLine(border, border, width() - border, height - border);
+ painter.drawLine(border, height - border, width() - border, border);
+}
+
+void ClearButton::textChanged(const QString &text)
+{
+ setVisible(!text.isEmpty());
+}
+
+/*
+ Search icon on the left hand side of the search widget
+ When a menu is set a down arrow appears
+ */
+class SearchButton : public QAbstractButton {
+public:
+ SearchButton(QWidget *parent = 0);
+ void paintEvent(QPaintEvent *event);
+ QMenu *m_menu;
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+};
+
+SearchButton::SearchButton(QWidget *parent)
+ : QAbstractButton(parent),
+ m_menu(0)
+{
+ setObjectName(QLatin1String("SearchButton"));
+ setCursor(Qt::ArrowCursor);
+ setFocusPolicy(Qt::NoFocus);
+}
+
+void SearchButton::mousePressEvent(QMouseEvent *event)
+{
+ if (m_menu && event->button() == Qt::LeftButton) {
+ QWidget *p = parentWidget();
+ if (p) {
+ QPoint r = p->mapToGlobal(QPoint(0, p->height()));
+ m_menu->exec(QPoint(r.x() + height() / 2, r.y()));
+ }
+ event->accept();
+ }
+ QAbstractButton::mousePressEvent(event);
+}
+
+void SearchButton::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+ QPainterPath myPath;
+
+ int radius = (height() / 5) * 2;
+ QRect circle(height() / 3 - 1, height() / 4, radius, radius);
+ myPath.addEllipse(circle);
+
+ myPath.arcMoveTo(circle, 300);
+ QPointF c = myPath.currentPosition();
+ int diff = height() / 7;
+ myPath.lineTo(qMin(width() - 2, (int)c.x() + diff), c.y() + diff);
+
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.setPen(QPen(Qt::darkGray, 2));
+ painter.drawPath(myPath);
+
+ if (m_menu) {
+ QPainterPath dropPath;
+ dropPath.arcMoveTo(circle, 320);
+ QPointF c = dropPath.currentPosition();
+ c = QPointF(c.x() + 3.5, c.y() + 0.5);
+ dropPath.moveTo(c);
+ dropPath.lineTo(c.x() + 4, c.y());
+ dropPath.lineTo(c.x() + 2, c.y() + 2);
+ dropPath.closeSubpath();
+ painter.setPen(Qt::darkGray);
+ painter.setBrush(Qt::darkGray);
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ painter.drawPath(dropPath);
+ }
+ painter.end();
+}
+
+/*
+ SearchLineEdit is an enhanced QLineEdit
+ - A Search icon on the left with optional menu
+ - When there is no text and doesn't have focus an "inactive text" is displayed
+ - When there is text a clear button is displayed on the right hand side
+ */
+SearchLineEdit::SearchLineEdit(QWidget *parent) : ExLineEdit(parent),
+ m_searchButton(new SearchButton(this))
+{
+ connect(lineEdit(), SIGNAL(textChanged(const QString &)),
+ this, SIGNAL(textChanged(const QString &)));
+ setLeftWidget(m_searchButton);
+ m_inactiveText = tr("Search");
+
+ QSizePolicy policy = sizePolicy();
+ setSizePolicy(QSizePolicy::Preferred, policy.verticalPolicy());
+}
+
+void SearchLineEdit::paintEvent(QPaintEvent *event)
+{
+ if (lineEdit()->text().isEmpty() && !hasFocus() && !m_inactiveText.isEmpty()) {
+ ExLineEdit::paintEvent(event);
+ QStyleOptionFrameV2 panel;
+ initStyleOption(&panel);
+ QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
+ QFontMetrics fm = fontMetrics();
+ int horizontalMargin = lineEdit()->x();
+ QRect lineRect(horizontalMargin + r.x(), r.y() + (r.height() - fm.height() + 1) / 2,
+ r.width() - 2 * horizontalMargin, fm.height());
+ QPainter painter(this);
+ painter.setPen(palette().brush(QPalette::Disabled, QPalette::Text).color());
+ painter.drawText(lineRect, Qt::AlignLeft|Qt::AlignVCenter, m_inactiveText);
+ } else {
+ ExLineEdit::paintEvent(event);
+ }
+}
+
+void SearchLineEdit::resizeEvent(QResizeEvent *event)
+{
+ updateGeometries();
+ ExLineEdit::resizeEvent(event);
+}
+
+void SearchLineEdit::updateGeometries()
+{
+ int menuHeight = height();
+ int menuWidth = menuHeight + 1;
+ if (!m_searchButton->m_menu)
+ menuWidth = (menuHeight / 5) * 4;
+ m_searchButton->resize(QSize(menuWidth, menuHeight));
+}
+
+QString SearchLineEdit::inactiveText() const
+{
+ return m_inactiveText;
+}
+
+void SearchLineEdit::setInactiveText(const QString &text)
+{
+ m_inactiveText = text;
+}
+
+void SearchLineEdit::setMenu(QMenu *menu)
+{
+ if (m_searchButton->m_menu)
+ m_searchButton->m_menu->deleteLater();
+ m_searchButton->m_menu = menu;
+ updateGeometries();
+}
+
+QMenu *SearchLineEdit::menu() const
+{
+ if (!m_searchButton->m_menu) {
+ m_searchButton->m_menu = new QMenu(m_searchButton);
+ if (isVisible())
+ (const_cast<SearchLineEdit*>(this))->updateGeometries();
+ }
+ return m_searchButton->m_menu;
+}
+
diff --git a/demos/browser/searchlineedit.h b/demos/browser/searchlineedit.h
new file mode 100644
index 0000000..be17e05
--- /dev/null
+++ b/demos/browser/searchlineedit.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SEARCHLINEEDIT_H
+#define SEARCHLINEEDIT_H
+
+#include "urllineedit.h"
+
+#include <QtGui/QLineEdit>
+#include <QtGui/QAbstractButton>
+
+QT_BEGIN_NAMESPACE
+class QMenu;
+QT_END_NAMESPACE
+
+class SearchButton;
+
+/*
+ Clear button on the right hand side of the search widget.
+ Hidden by default
+ "A circle with an X in it"
+ */
+class ClearButton : public QAbstractButton
+{
+ Q_OBJECT
+
+public:
+ ClearButton(QWidget *parent = 0);
+ void paintEvent(QPaintEvent *event);
+
+public slots:
+ void textChanged(const QString &text);
+};
+
+
+class SearchLineEdit : public ExLineEdit
+{
+ Q_OBJECT
+ Q_PROPERTY(QString inactiveText READ inactiveText WRITE setInactiveText)
+
+signals:
+ void textChanged(const QString &text);
+
+public:
+ SearchLineEdit(QWidget *parent = 0);
+
+ QString inactiveText() const;
+ void setInactiveText(const QString &text);
+
+ QMenu *menu() const;
+ void setMenu(QMenu *menu);
+
+protected:
+ void resizeEvent(QResizeEvent *event);
+ void paintEvent(QPaintEvent *event);
+
+private:
+ void updateGeometries();
+
+ SearchButton *m_searchButton;
+ QString m_inactiveText;
+};
+
+#endif // SEARCHLINEEDIT_H
+
diff --git a/demos/browser/settings.cpp b/demos/browser/settings.cpp
new file mode 100644
index 0000000..09f4846
--- /dev/null
+++ b/demos/browser/settings.cpp
@@ -0,0 +1,324 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "settings.h"
+
+#include "browserapplication.h"
+#include "browsermainwindow.h"
+#include "cookiejar.h"
+#include "history.h"
+#include "networkaccessmanager.h"
+#include "webview.h"
+
+#include <QtCore/QSettings>
+#include <QtGui/QtGui>
+#include <QtWebKit/QtWebKit>
+
+SettingsDialog::SettingsDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ setupUi(this);
+ connect(exceptionsButton, SIGNAL(clicked()), this, SLOT(showExceptions()));
+ connect(setHomeToCurrentPageButton, SIGNAL(clicked()), this, SLOT(setHomeToCurrentPage()));
+ connect(cookiesButton, SIGNAL(clicked()), this, SLOT(showCookies()));
+ connect(standardFontButton, SIGNAL(clicked()), this, SLOT(chooseFont()));
+ connect(fixedFontButton, SIGNAL(clicked()), this, SLOT(chooseFixedFont()));
+
+ loadDefaults();
+ loadFromSettings();
+}
+
+void SettingsDialog::loadDefaults()
+{
+ QWebSettings *defaultSettings = QWebSettings::globalSettings();
+ QString standardFontFamily = defaultSettings->fontFamily(QWebSettings::StandardFont);
+ int standardFontSize = defaultSettings->fontSize(QWebSettings::DefaultFontSize);
+ standardFont = QFont(standardFontFamily, standardFontSize);
+ standardLabel->setText(QString(QLatin1String("%1 %2")).arg(standardFont.family()).arg(standardFont.pointSize()));
+
+ QString fixedFontFamily = defaultSettings->fontFamily(QWebSettings::FixedFont);
+ int fixedFontSize = defaultSettings->fontSize(QWebSettings::DefaultFixedFontSize);
+ fixedFont = QFont(fixedFontFamily, fixedFontSize);
+ fixedLabel->setText(QString(QLatin1String("%1 %2")).arg(fixedFont.family()).arg(fixedFont.pointSize()));
+
+ downloadsLocation->setText(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation));
+
+ enableJavascript->setChecked(defaultSettings->testAttribute(QWebSettings::JavascriptEnabled));
+ enablePlugins->setChecked(defaultSettings->testAttribute(QWebSettings::PluginsEnabled));
+}
+
+void SettingsDialog::loadFromSettings()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("MainWindow"));
+ QString defaultHome = QLatin1String("http://qtsoftware.com");
+ homeLineEdit->setText(settings.value(QLatin1String("home"), defaultHome).toString());
+ settings.endGroup();
+
+ settings.beginGroup(QLatin1String("history"));
+ int historyExpire = settings.value(QLatin1String("historyExpire")).toInt();
+ int idx = 0;
+ switch (historyExpire) {
+ case 1: idx = 0; break;
+ case 7: idx = 1; break;
+ case 14: idx = 2; break;
+ case 30: idx = 3; break;
+ case 365: idx = 4; break;
+ case -1: idx = 5; break;
+ default:
+ idx = 5;
+ }
+ expireHistory->setCurrentIndex(idx);
+ settings.endGroup();
+
+ settings.beginGroup(QLatin1String("downloadmanager"));
+ QString downloadDirectory = settings.value(QLatin1String("downloadDirectory"), downloadsLocation->text()).toString();
+ downloadsLocation->setText(downloadDirectory);
+ settings.endGroup();
+
+ settings.beginGroup(QLatin1String("general"));
+ openLinksIn->setCurrentIndex(settings.value(QLatin1String("openLinksIn"), openLinksIn->currentIndex()).toInt());
+
+ settings.endGroup();
+
+ // Appearance
+ settings.beginGroup(QLatin1String("websettings"));
+ fixedFont = qVariantValue<QFont>(settings.value(QLatin1String("fixedFont"), fixedFont));
+ standardFont = qVariantValue<QFont>(settings.value(QLatin1String("standardFont"), standardFont));
+
+ standardLabel->setText(QString(QLatin1String("%1 %2")).arg(standardFont.family()).arg(standardFont.pointSize()));
+ fixedLabel->setText(QString(QLatin1String("%1 %2")).arg(fixedFont.family()).arg(fixedFont.pointSize()));
+
+ enableJavascript->setChecked(settings.value(QLatin1String("enableJavascript"), enableJavascript->isChecked()).toBool());
+ enablePlugins->setChecked(settings.value(QLatin1String("enablePlugins"), enablePlugins->isChecked()).toBool());
+ userStyleSheet->setText(settings.value(QLatin1String("userStyleSheet")).toUrl().toString());
+ settings.endGroup();
+
+ // Privacy
+ settings.beginGroup(QLatin1String("cookies"));
+
+ CookieJar *jar = BrowserApplication::cookieJar();
+ QByteArray value = settings.value(QLatin1String("acceptCookies"), QLatin1String("AcceptOnlyFromSitesNavigatedTo")).toByteArray();
+ QMetaEnum acceptPolicyEnum = jar->staticMetaObject.enumerator(jar->staticMetaObject.indexOfEnumerator("AcceptPolicy"));
+ CookieJar::AcceptPolicy acceptCookies = acceptPolicyEnum.keyToValue(value) == -1 ?
+ CookieJar::AcceptOnlyFromSitesNavigatedTo :
+ static_cast<CookieJar::AcceptPolicy>(acceptPolicyEnum.keyToValue(value));
+ switch(acceptCookies) {
+ case CookieJar::AcceptAlways:
+ acceptCombo->setCurrentIndex(0);
+ break;
+ case CookieJar::AcceptNever:
+ acceptCombo->setCurrentIndex(1);
+ break;
+ case CookieJar::AcceptOnlyFromSitesNavigatedTo:
+ acceptCombo->setCurrentIndex(2);
+ break;
+ }
+
+ value = settings.value(QLatin1String("keepCookiesUntil"), QLatin1String("Expire")).toByteArray();
+ QMetaEnum keepPolicyEnum = jar->staticMetaObject.enumerator(jar->staticMetaObject.indexOfEnumerator("KeepPolicy"));
+ CookieJar::KeepPolicy keepCookies = keepPolicyEnum.keyToValue(value) == -1 ?
+ CookieJar::KeepUntilExpire :
+ static_cast<CookieJar::KeepPolicy>(keepPolicyEnum.keyToValue(value));
+ switch(keepCookies) {
+ case CookieJar::KeepUntilExpire:
+ keepUntilCombo->setCurrentIndex(0);
+ break;
+ case CookieJar::KeepUntilExit:
+ keepUntilCombo->setCurrentIndex(1);
+ break;
+ case CookieJar::KeepUntilTimeLimit:
+ keepUntilCombo->setCurrentIndex(2);
+ break;
+ }
+ settings.endGroup();
+
+
+ // Proxy
+ settings.beginGroup(QLatin1String("proxy"));
+ proxySupport->setChecked(settings.value(QLatin1String("enabled"), false).toBool());
+ proxyType->setCurrentIndex(settings.value(QLatin1String("type"), 0).toInt());
+ proxyHostName->setText(settings.value(QLatin1String("hostName")).toString());
+ proxyPort->setValue(settings.value(QLatin1String("port"), 1080).toInt());
+ proxyUserName->setText(settings.value(QLatin1String("userName")).toString());
+ proxyPassword->setText(settings.value(QLatin1String("password")).toString());
+ settings.endGroup();
+}
+
+void SettingsDialog::saveToSettings()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("MainWindow"));
+ settings.setValue(QLatin1String("home"), homeLineEdit->text());
+ settings.endGroup();
+
+ settings.beginGroup(QLatin1String("general"));
+ settings.setValue(QLatin1String("openLinksIn"), openLinksIn->currentIndex());
+ settings.endGroup();
+
+ settings.beginGroup(QLatin1String("history"));
+ int historyExpire = expireHistory->currentIndex();
+ int idx = -1;
+ switch (historyExpire) {
+ case 0: idx = 1; break;
+ case 1: idx = 7; break;
+ case 2: idx = 14; break;
+ case 3: idx = 30; break;
+ case 4: idx = 365; break;
+ case 5: idx = -1; break;
+ }
+ settings.setValue(QLatin1String("historyExpire"), idx);
+ settings.endGroup();
+
+ // Appearance
+ settings.beginGroup(QLatin1String("websettings"));
+ settings.setValue(QLatin1String("fixedFont"), fixedFont);
+ settings.setValue(QLatin1String("standardFont"), standardFont);
+ settings.setValue(QLatin1String("enableJavascript"), enableJavascript->isChecked());
+ settings.setValue(QLatin1String("enablePlugins"), enablePlugins->isChecked());
+ QString userStyleSheetString = userStyleSheet->text();
+ if (QFile::exists(userStyleSheetString))
+ settings.setValue(QLatin1String("userStyleSheet"), QUrl::fromLocalFile(userStyleSheetString));
+ else
+ settings.setValue(QLatin1String("userStyleSheet"), QUrl(userStyleSheetString));
+ settings.endGroup();
+
+ //Privacy
+ settings.beginGroup(QLatin1String("cookies"));
+
+ CookieJar::KeepPolicy keepCookies;
+ switch(acceptCombo->currentIndex()) {
+ default:
+ case 0:
+ keepCookies = CookieJar::KeepUntilExpire;
+ break;
+ case 1:
+ keepCookies = CookieJar::KeepUntilExit;
+ break;
+ case 2:
+ keepCookies = CookieJar::KeepUntilTimeLimit;
+ break;
+ }
+ CookieJar *jar = BrowserApplication::cookieJar();
+ QMetaEnum acceptPolicyEnum = jar->staticMetaObject.enumerator(jar->staticMetaObject.indexOfEnumerator("AcceptPolicy"));
+ settings.setValue(QLatin1String("acceptCookies"), QLatin1String(acceptPolicyEnum.valueToKey(keepCookies)));
+
+ CookieJar::KeepPolicy keepPolicy;
+ switch(keepUntilCombo->currentIndex()) {
+ default:
+ case 0:
+ keepPolicy = CookieJar::KeepUntilExpire;
+ break;
+ case 1:
+ keepPolicy = CookieJar::KeepUntilExit;
+ break;
+ case 2:
+ keepPolicy = CookieJar::KeepUntilTimeLimit;
+ break;
+ }
+
+ QMetaEnum keepPolicyEnum = jar->staticMetaObject.enumerator(jar->staticMetaObject.indexOfEnumerator("KeepPolicy"));
+ settings.setValue(QLatin1String("keepCookiesUntil"), QLatin1String(keepPolicyEnum.valueToKey(keepPolicy)));
+
+ settings.endGroup();
+
+ // proxy
+ settings.beginGroup(QLatin1String("proxy"));
+ settings.setValue(QLatin1String("enabled"), proxySupport->isChecked());
+ settings.setValue(QLatin1String("type"), proxyType->currentIndex());
+ settings.setValue(QLatin1String("hostName"), proxyHostName->text());
+ settings.setValue(QLatin1String("port"), proxyPort->text());
+ settings.setValue(QLatin1String("userName"), proxyUserName->text());
+ settings.setValue(QLatin1String("password"), proxyPassword->text());
+ settings.endGroup();
+
+ BrowserApplication::instance()->loadSettings();
+ BrowserApplication::networkAccessManager()->loadSettings();
+ BrowserApplication::cookieJar()->loadSettings();
+ BrowserApplication::historyManager()->loadSettings();
+}
+
+void SettingsDialog::accept()
+{
+ saveToSettings();
+ QDialog::accept();
+}
+
+void SettingsDialog::showCookies()
+{
+ CookiesDialog *dialog = new CookiesDialog(BrowserApplication::cookieJar(), this);
+ dialog->exec();
+}
+
+void SettingsDialog::showExceptions()
+{
+ CookiesExceptionsDialog *dialog = new CookiesExceptionsDialog(BrowserApplication::cookieJar(), this);
+ dialog->exec();
+}
+
+void SettingsDialog::chooseFont()
+{
+ bool ok;
+ QFont font = QFontDialog::getFont(&ok, standardFont, this);
+ if ( ok ) {
+ standardFont = font;
+ standardLabel->setText(QString(QLatin1String("%1 %2")).arg(font.family()).arg(font.pointSize()));
+ }
+}
+
+void SettingsDialog::chooseFixedFont()
+{
+ bool ok;
+ QFont font = QFontDialog::getFont(&ok, fixedFont, this);
+ if ( ok ) {
+ fixedFont = font;
+ fixedLabel->setText(QString(QLatin1String("%1 %2")).arg(font.family()).arg(font.pointSize()));
+ }
+}
+
+void SettingsDialog::setHomeToCurrentPage()
+{
+ BrowserMainWindow *mw = static_cast<BrowserMainWindow*>(parent());
+ WebView *webView = mw->currentTab();
+ if (webView)
+ homeLineEdit->setText(webView->url().toString());
+}
+
diff --git a/demos/browser/settings.h b/demos/browser/settings.h
new file mode 100644
index 0000000..a7a0a35
--- /dev/null
+++ b/demos/browser/settings.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+#include <QtGui/QDialog>
+#include "ui_settings.h"
+
+class SettingsDialog : public QDialog, public Ui_Settings
+{
+ Q_OBJECT
+
+public:
+ SettingsDialog(QWidget *parent = 0);
+ void accept();
+
+private slots:
+ void loadDefaults();
+ void loadFromSettings();
+ void saveToSettings();
+
+ void setHomeToCurrentPage();
+ void showCookies();
+ void showExceptions();
+
+ void chooseFont();
+ void chooseFixedFont();
+
+private:
+ QFont standardFont;
+ QFont fixedFont;
+};
+
+#endif // SETTINGS_H
+
diff --git a/demos/browser/settings.ui b/demos/browser/settings.ui
new file mode 100644
index 0000000..3491ce0
--- /dev/null
+++ b/demos/browser/settings.ui
@@ -0,0 +1,614 @@
+<ui version="4.0" >
+ <class>Settings</class>
+ <widget class="QDialog" name="Settings" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>657</width>
+ <height>322</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Settings</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="2" column="0" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QTabWidget" name="tabWidget" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>627</width>
+ <height>243</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>General</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_4" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Home:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2" >
+ <widget class="QLineEdit" name="homeLineEdit" />
+ </item>
+ <item row="1" column="1" >
+ <widget class="QPushButton" name="setHomeToCurrentPageButton" >
+ <property name="text" >
+ <string>Set to current page</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <spacer name="horizontalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>280</width>
+ <height>18</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_4" >
+ <property name="text" >
+ <string>Remove history items:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" colspan="2" >
+ <widget class="QComboBox" name="expireHistory" >
+ <item>
+ <property name="text" >
+ <string>After one day</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>After one week</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>After two weeks</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>After one month</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>After one year</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Manually</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_7" >
+ <property name="text" >
+ <string>Save downloads to:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2" >
+ <widget class="QLineEdit" name="downloadsLocation" />
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_8" >
+ <property name="text" >
+ <string>Open links from applications:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" colspan="2" >
+ <widget class="QComboBox" name="openLinksIn" >
+ <item>
+ <property name="text" >
+ <string>In a tab in the current window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>In a new window</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="5" column="1" colspan="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>391</width>
+ <height>262</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_3" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>627</width>
+ <height>243</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>Appearance</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_3" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>Standard font:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLabel" name="standardLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="text" >
+ <string>Times 16</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QPushButton" name="standardFontButton" >
+ <property name="text" >
+ <string>Select...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_6" >
+ <property name="text" >
+ <string>Fixed-width font:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLabel" name="fixedLabel" >
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="text" >
+ <string>Courier 13</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QPushButton" name="fixedFontButton" >
+ <property name="text" >
+ <string>Select...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>93</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_2" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>627</width>
+ <height>243</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>Privacy</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3" >
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="title" >
+ <string>Web Content</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2" >
+ <item>
+ <widget class="QCheckBox" name="enablePlugins" >
+ <property name="text" >
+ <string>Enable Plugins</string>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="enableJavascript" >
+ <property name="text" >
+ <string>Enable Javascript</string>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="cookiesGroupBox" >
+ <property name="title" >
+ <string>Cookies</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Accept Cookies:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="acceptCombo" >
+ <item>
+ <property name="text" >
+ <string>Always</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Never</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Only from sites you navigate to</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QPushButton" name="exceptionsButton" >
+ <property name="text" >
+ <string>Exceptions...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Keep until:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="keepUntilCombo" >
+ <item>
+ <property name="text" >
+ <string>They expire</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>I exit the application</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>At most 90 days</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QPushButton" name="cookiesButton" >
+ <property name="text" >
+ <string>Cookies...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>371</width>
+ <height>177</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_4" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>627</width>
+ <height>243</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>Proxy</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QGroupBox" name="proxySupport" >
+ <property name="title" >
+ <string>Enable proxy</string>
+ </property>
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_6" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_9" >
+ <property name="text" >
+ <string>Type:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2" >
+ <widget class="QComboBox" name="proxyType" >
+ <item>
+ <property name="text" >
+ <string>Socks5</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Http</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_10" >
+ <property name="text" >
+ <string>Host:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2" >
+ <widget class="QLineEdit" name="proxyHostName" />
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_11" >
+ <property name="text" >
+ <string>Port:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QSpinBox" name="proxyPort" >
+ <property name="maximum" >
+ <number>10000</number>
+ </property>
+ <property name="value" >
+ <number>1080</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" >
+ <spacer name="horizontalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>293</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_12" >
+ <property name="text" >
+ <string>User Name:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2" >
+ <widget class="QLineEdit" name="proxyUserName" />
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_13" >
+ <property name="text" >
+ <string>Password:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" colspan="2" >
+ <widget class="QLineEdit" name="proxyPassword" >
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <spacer name="verticalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>8</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_5" >
+ <attribute name="title" >
+ <string>Advanced</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_2" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_14" >
+ <property name="text" >
+ <string>Style Sheet:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="userStyleSheet" />
+ </item>
+ <item row="1" column="1" >
+ <spacer name="verticalSpacer_3" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>176</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Settings</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Settings</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/demos/browser/squeezelabel.cpp b/demos/browser/squeezelabel.cpp
new file mode 100644
index 0000000..3209e16
--- /dev/null
+++ b/demos/browser/squeezelabel.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "squeezelabel.h"
+
+SqueezeLabel::SqueezeLabel(QWidget *parent) : QLabel(parent)
+{
+}
+
+void SqueezeLabel::paintEvent(QPaintEvent *event)
+{
+ QFontMetrics fm = fontMetrics();
+ if (fm.width(text()) > contentsRect().width()) {
+ QString elided = fm.elidedText(text(), Qt::ElideMiddle, width());
+ QString oldText = text();
+ setText(elided);
+ QLabel::paintEvent(event);
+ setText(oldText);
+ } else {
+ QLabel::paintEvent(event);
+ }
+}
+
diff --git a/demos/browser/squeezelabel.h b/demos/browser/squeezelabel.h
new file mode 100644
index 0000000..2f82240
--- /dev/null
+++ b/demos/browser/squeezelabel.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SQUEEZELABEL_H
+#define SQUEEZELABEL_H
+
+#include <QtGui/QLabel>
+
+class SqueezeLabel : public QLabel
+{
+ Q_OBJECT
+
+public:
+ SqueezeLabel(QWidget *parent = 0);
+
+protected:
+ void paintEvent(QPaintEvent *event);
+
+};
+
+#endif // SQUEEZELABEL_H
+
diff --git a/demos/browser/tabwidget.cpp b/demos/browser/tabwidget.cpp
new file mode 100644
index 0000000..7a2ee40
--- /dev/null
+++ b/demos/browser/tabwidget.cpp
@@ -0,0 +1,830 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "tabwidget.h"
+
+#include "browserapplication.h"
+#include "browsermainwindow.h"
+#include "history.h"
+#include "urllineedit.h"
+#include "webview.h"
+
+#include <QtGui/QClipboard>
+#include <QtGui/QCompleter>
+#include <QtGui/QListView>
+#include <QtGui/QMenu>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QStackedWidget>
+#include <QtGui/QStyle>
+#include <QtGui/QToolButton>
+
+#include <QtCore/QDebug>
+
+TabBar::TabBar(QWidget *parent)
+ : QTabBar(parent)
+{
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ setAcceptDrops(true);
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(contextMenuRequested(const QPoint &)));
+
+ QString alt = QLatin1String("Alt+%1");
+ for (int i = 1; i <= 10; ++i) {
+ int key = i;
+ if (key == 10)
+ key = 0;
+ QShortcut *shortCut = new QShortcut(alt.arg(key), this);
+ m_tabShortcuts.append(shortCut);
+ connect(shortCut, SIGNAL(activated()), this, SLOT(selectTabAction()));
+ }
+ setTabsClosable(true);
+ connect(this, SIGNAL(tabCloseRequested(int)),
+ this, SIGNAL(closeTab(int)));
+ setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab);
+ setMovable(true);
+}
+
+void TabBar::selectTabAction()
+{
+ if (QShortcut *shortCut = qobject_cast<QShortcut*>(sender())) {
+ int index = m_tabShortcuts.indexOf(shortCut);
+ if (index == 0)
+ index = 10;
+ setCurrentIndex(index);
+ }
+}
+
+void TabBar::contextMenuRequested(const QPoint &position)
+{
+ QMenu menu;
+ menu.addAction(tr("New &Tab"), this, SIGNAL(newTab()), QKeySequence::AddTab);
+ int index = tabAt(position);
+ if (-1 != index) {
+ QAction *action = menu.addAction(tr("Clone Tab"),
+ this, SLOT(cloneTab()));
+ action->setData(index);
+
+ menu.addSeparator();
+
+ action = menu.addAction(tr("&Close Tab"),
+ this, SLOT(closeTab()), QKeySequence::Close);
+ action->setData(index);
+
+ action = menu.addAction(tr("Close &Other Tabs"),
+ this, SLOT(closeOtherTabs()));
+ action->setData(index);
+
+ menu.addSeparator();
+
+ action = menu.addAction(tr("Reload Tab"),
+ this, SLOT(reloadTab()), QKeySequence::Refresh);
+ action->setData(index);
+ } else {
+ menu.addSeparator();
+ }
+ menu.addAction(tr("Reload All Tabs"), this, SIGNAL(reloadAllTabs()));
+ menu.exec(QCursor::pos());
+}
+
+void TabBar::cloneTab()
+{
+ if (QAction *action = qobject_cast<QAction*>(sender())) {
+ int index = action->data().toInt();
+ emit cloneTab(index);
+ }
+}
+
+void TabBar::closeTab()
+{
+ if (QAction *action = qobject_cast<QAction*>(sender())) {
+ int index = action->data().toInt();
+ emit closeTab(index);
+ }
+}
+
+void TabBar::closeOtherTabs()
+{
+ if (QAction *action = qobject_cast<QAction*>(sender())) {
+ int index = action->data().toInt();
+ emit closeOtherTabs(index);
+ }
+}
+
+void TabBar::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton)
+ m_dragStartPos = event->pos();
+ QTabBar::mousePressEvent(event);
+}
+
+void TabBar::mouseMoveEvent(QMouseEvent *event)
+{
+ if (event->buttons() == Qt::LeftButton) {
+ int diffX = event->pos().x() - m_dragStartPos.x();
+ int diffY = event->pos().y() - m_dragStartPos.y();
+ if ((event->pos() - m_dragStartPos).manhattanLength() > QApplication::startDragDistance()
+ && diffX < 3 && diffX > -3
+ && diffY < -10) {
+ QDrag *drag = new QDrag(this);
+ QMimeData *mimeData = new QMimeData;
+ QList<QUrl> urls;
+ int index = tabAt(event->pos());
+ QUrl url = tabData(index).toUrl();
+ urls.append(url);
+ mimeData->setUrls(urls);
+ mimeData->setText(tabText(index));
+ mimeData->setData(QLatin1String("action"), "tab-reordering");
+ drag->setMimeData(mimeData);
+ drag->exec();
+ }
+ }
+ QTabBar::mouseMoveEvent(event);
+}
+
+// When index is -1 index chooses the current tab
+void TabWidget::reloadTab(int index)
+{
+ if (index < 0)
+ index = currentIndex();
+ if (index < 0 || index >= count())
+ return;
+
+ QWidget *widget = this->widget(index);
+ if (WebView *tab = qobject_cast<WebView*>(widget))
+ tab->reload();
+}
+
+void TabBar::reloadTab()
+{
+ if (QAction *action = qobject_cast<QAction*>(sender())) {
+ int index = action->data().toInt();
+ emit reloadTab(index);
+ }
+}
+
+TabWidget::TabWidget(QWidget *parent)
+ : QTabWidget(parent)
+ , m_recentlyClosedTabsAction(0)
+ , m_newTabAction(0)
+ , m_closeTabAction(0)
+ , m_nextTabAction(0)
+ , m_previousTabAction(0)
+ , m_recentlyClosedTabsMenu(0)
+ , m_lineEditCompleter(0)
+ , m_lineEdits(0)
+ , m_tabBar(new TabBar(this))
+{
+ setElideMode(Qt::ElideRight);
+
+ connect(m_tabBar, SIGNAL(newTab()), this, SLOT(newTab()));
+ connect(m_tabBar, SIGNAL(closeTab(int)), this, SLOT(closeTab(int)));
+ connect(m_tabBar, SIGNAL(cloneTab(int)), this, SLOT(cloneTab(int)));
+ connect(m_tabBar, SIGNAL(closeOtherTabs(int)), this, SLOT(closeOtherTabs(int)));
+ connect(m_tabBar, SIGNAL(reloadTab(int)), this, SLOT(reloadTab(int)));
+ connect(m_tabBar, SIGNAL(reloadAllTabs()), this, SLOT(reloadAllTabs()));
+ connect(m_tabBar, SIGNAL(tabMoved(int, int)), this, SLOT(moveTab(int, int)));
+ setTabBar(m_tabBar);
+ setDocumentMode(true);
+
+ // Actions
+ m_newTabAction = new QAction(QIcon(QLatin1String(":addtab.png")), tr("New &Tab"), this);
+ m_newTabAction->setShortcuts(QKeySequence::AddTab);
+ m_newTabAction->setIconVisibleInMenu(false);
+ connect(m_newTabAction, SIGNAL(triggered()), this, SLOT(newTab()));
+
+ m_closeTabAction = new QAction(QIcon(QLatin1String(":closetab.png")), tr("&Close Tab"), this);
+ m_closeTabAction->setShortcuts(QKeySequence::Close);
+ m_closeTabAction->setIconVisibleInMenu(false);
+ connect(m_closeTabAction, SIGNAL(triggered()), this, SLOT(closeTab()));
+
+ m_nextTabAction = new QAction(tr("Show Next Tab"), this);
+ QList<QKeySequence> shortcuts;
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BraceRight));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_PageDown));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BracketRight));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Less));
+ m_nextTabAction->setShortcuts(shortcuts);
+ connect(m_nextTabAction, SIGNAL(triggered()), this, SLOT(nextTab()));
+
+ m_previousTabAction = new QAction(tr("Show Previous Tab"), this);
+ shortcuts.clear();
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BraceLeft));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_PageUp));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BracketLeft));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Greater));
+ m_previousTabAction->setShortcuts(shortcuts);
+ connect(m_previousTabAction, SIGNAL(triggered()), this, SLOT(previousTab()));
+
+ m_recentlyClosedTabsMenu = new QMenu(this);
+ connect(m_recentlyClosedTabsMenu, SIGNAL(aboutToShow()),
+ this, SLOT(aboutToShowRecentTabsMenu()));
+ connect(m_recentlyClosedTabsMenu, SIGNAL(triggered(QAction *)),
+ this, SLOT(aboutToShowRecentTriggeredAction(QAction *)));
+ m_recentlyClosedTabsAction = new QAction(tr("Recently Closed Tabs"), this);
+ m_recentlyClosedTabsAction->setMenu(m_recentlyClosedTabsMenu);
+ m_recentlyClosedTabsAction->setEnabled(false);
+
+ connect(this, SIGNAL(currentChanged(int)),
+ this, SLOT(currentChanged(int)));
+
+ m_lineEdits = new QStackedWidget(this);
+}
+
+void TabWidget::clear()
+{
+ // clear the recently closed tabs
+ m_recentlyClosedTabs.clear();
+ // clear the line edit history
+ for (int i = 0; i < m_lineEdits->count(); ++i) {
+ QLineEdit *qLineEdit = lineEdit(i);
+ qLineEdit->setText(qLineEdit->text());
+ }
+}
+
+void TabWidget::moveTab(int fromIndex, int toIndex)
+{
+ QWidget *lineEdit = m_lineEdits->widget(fromIndex);
+ m_lineEdits->removeWidget(lineEdit);
+ m_lineEdits->insertWidget(toIndex, lineEdit);
+}
+
+void TabWidget::addWebAction(QAction *action, QWebPage::WebAction webAction)
+{
+ if (!action)
+ return;
+ m_actions.append(new WebActionMapper(action, webAction, this));
+}
+
+void TabWidget::currentChanged(int index)
+{
+ WebView *webView = this->webView(index);
+ if (!webView)
+ return;
+
+ Q_ASSERT(m_lineEdits->count() == count());
+
+ WebView *oldWebView = this->webView(m_lineEdits->currentIndex());
+ if (oldWebView) {
+ disconnect(oldWebView, SIGNAL(statusBarMessage(const QString&)),
+ this, SIGNAL(showStatusBarMessage(const QString&)));
+ disconnect(oldWebView->page(), SIGNAL(linkHovered(const QString&, const QString&, const QString&)),
+ this, SIGNAL(linkHovered(const QString&)));
+ disconnect(oldWebView, SIGNAL(loadProgress(int)),
+ this, SIGNAL(loadProgress(int)));
+ }
+
+ connect(webView, SIGNAL(statusBarMessage(const QString&)),
+ this, SIGNAL(showStatusBarMessage(const QString&)));
+ connect(webView->page(), SIGNAL(linkHovered(const QString&, const QString&, const QString&)),
+ this, SIGNAL(linkHovered(const QString&)));
+ connect(webView, SIGNAL(loadProgress(int)),
+ this, SIGNAL(loadProgress(int)));
+
+ for (int i = 0; i < m_actions.count(); ++i) {
+ WebActionMapper *mapper = m_actions[i];
+ mapper->updateCurrent(webView->page());
+ }
+ emit setCurrentTitle(webView->title());
+ m_lineEdits->setCurrentIndex(index);
+ emit loadProgress(webView->progress());
+ emit showStatusBarMessage(webView->lastStatusBarText());
+ if (webView->url().isEmpty())
+ m_lineEdits->currentWidget()->setFocus();
+ else
+ webView->setFocus();
+}
+
+QAction *TabWidget::newTabAction() const
+{
+ return m_newTabAction;
+}
+
+QAction *TabWidget::closeTabAction() const
+{
+ return m_closeTabAction;
+}
+
+QAction *TabWidget::recentlyClosedTabsAction() const
+{
+ return m_recentlyClosedTabsAction;
+}
+
+QAction *TabWidget::nextTabAction() const
+{
+ return m_nextTabAction;
+}
+
+QAction *TabWidget::previousTabAction() const
+{
+ return m_previousTabAction;
+}
+
+QWidget *TabWidget::lineEditStack() const
+{
+ return m_lineEdits;
+}
+
+QLineEdit *TabWidget::currentLineEdit() const
+{
+ return lineEdit(m_lineEdits->currentIndex());
+}
+
+WebView *TabWidget::currentWebView() const
+{
+ return webView(currentIndex());
+}
+
+QLineEdit *TabWidget::lineEdit(int index) const
+{
+ UrlLineEdit *urlLineEdit = qobject_cast<UrlLineEdit*>(m_lineEdits->widget(index));
+ if (urlLineEdit)
+ return urlLineEdit->lineEdit();
+ return 0;
+}
+
+WebView *TabWidget::webView(int index) const
+{
+ QWidget *widget = this->widget(index);
+ if (WebView *webView = qobject_cast<WebView*>(widget)) {
+ return webView;
+ } else {
+ // optimization to delay creating the first webview
+ if (count() == 1) {
+ TabWidget *that = const_cast<TabWidget*>(this);
+ that->setUpdatesEnabled(false);
+ that->newTab();
+ that->closeTab(0);
+ that->setUpdatesEnabled(true);
+ return currentWebView();
+ }
+ }
+ return 0;
+}
+
+int TabWidget::webViewIndex(WebView *webView) const
+{
+ int index = indexOf(webView);
+ return index;
+}
+
+WebView *TabWidget::newTab(bool makeCurrent)
+{
+ // line edit
+ UrlLineEdit *urlLineEdit = new UrlLineEdit;
+ QLineEdit *lineEdit = urlLineEdit->lineEdit();
+ if (!m_lineEditCompleter && count() > 0) {
+ HistoryCompletionModel *completionModel = new HistoryCompletionModel(this);
+ completionModel->setSourceModel(BrowserApplication::historyManager()->historyFilterModel());
+ m_lineEditCompleter = new QCompleter(completionModel, this);
+ // Should this be in Qt by default?
+ QAbstractItemView *popup = m_lineEditCompleter->popup();
+ QListView *listView = qobject_cast<QListView*>(popup);
+ if (listView)
+ listView->setUniformItemSizes(true);
+ }
+ lineEdit->setCompleter(m_lineEditCompleter);
+ connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(lineEditReturnPressed()));
+ m_lineEdits->addWidget(urlLineEdit);
+ m_lineEdits->setSizePolicy(lineEdit->sizePolicy());
+
+ // optimization to delay creating the more expensive WebView, history, etc
+ if (count() == 0) {
+ QWidget *emptyWidget = new QWidget;
+ QPalette p = emptyWidget->palette();
+ p.setColor(QPalette::Window, palette().color(QPalette::Base));
+ emptyWidget->setPalette(p);
+ emptyWidget->setAutoFillBackground(true);
+ disconnect(this, SIGNAL(currentChanged(int)),
+ this, SLOT(currentChanged(int)));
+ addTab(emptyWidget, tr("(Untitled)"));
+ connect(this, SIGNAL(currentChanged(int)),
+ this, SLOT(currentChanged(int)));
+ return 0;
+ }
+
+ // webview
+ WebView *webView = new WebView;
+ urlLineEdit->setWebView(webView);
+ connect(webView, SIGNAL(loadStarted()),
+ this, SLOT(webViewLoadStarted()));
+ connect(webView, SIGNAL(loadFinished(bool)),
+ this, SLOT(webViewIconChanged()));
+ connect(webView, SIGNAL(iconChanged()),
+ this, SLOT(webViewIconChanged()));
+ connect(webView, SIGNAL(titleChanged(const QString &)),
+ this, SLOT(webViewTitleChanged(const QString &)));
+ connect(webView, SIGNAL(urlChanged(const QUrl &)),
+ this, SLOT(webViewUrlChanged(const QUrl &)));
+ connect(webView->page(), SIGNAL(windowCloseRequested()),
+ this, SLOT(windowCloseRequested()));
+ connect(webView->page(), SIGNAL(geometryChangeRequested(const QRect &)),
+ this, SIGNAL(geometryChangeRequested(const QRect &)));
+ connect(webView->page(), SIGNAL(printRequested(QWebFrame *)),
+ this, SIGNAL(printRequested(QWebFrame *)));
+ connect(webView->page(), SIGNAL(menuBarVisibilityChangeRequested(bool)),
+ this, SIGNAL(menuBarVisibilityChangeRequested(bool)));
+ connect(webView->page(), SIGNAL(statusBarVisibilityChangeRequested(bool)),
+ this, SIGNAL(statusBarVisibilityChangeRequested(bool)));
+ connect(webView->page(), SIGNAL(toolBarVisibilityChangeRequested(bool)),
+ this, SIGNAL(toolBarVisibilityChangeRequested(bool)));
+ addTab(webView, tr("(Untitled)"));
+ if (makeCurrent)
+ setCurrentWidget(webView);
+
+ // webview actions
+ for (int i = 0; i < m_actions.count(); ++i) {
+ WebActionMapper *mapper = m_actions[i];
+ mapper->addChild(webView->page()->action(mapper->webAction()));
+ }
+
+ if (count() == 1)
+ currentChanged(currentIndex());
+ emit tabsChanged();
+ return webView;
+}
+
+void TabWidget::reloadAllTabs()
+{
+ for (int i = 0; i < count(); ++i) {
+ QWidget *tabWidget = widget(i);
+ if (WebView *tab = qobject_cast<WebView*>(tabWidget)) {
+ tab->reload();
+ }
+ }
+}
+
+void TabWidget::lineEditReturnPressed()
+{
+ if (QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender())) {
+ emit loadPage(lineEdit->text());
+ if (m_lineEdits->currentWidget() == lineEdit)
+ currentWebView()->setFocus();
+ }
+}
+
+void TabWidget::windowCloseRequested()
+{
+ WebPage *webPage = qobject_cast<WebPage*>(sender());
+ WebView *webView = qobject_cast<WebView*>(webPage->view());
+ int index = webViewIndex(webView);
+ if (index >= 0) {
+ if (count() == 1)
+ webView->webPage()->mainWindow()->close();
+ else
+ closeTab(index);
+ }
+}
+
+void TabWidget::closeOtherTabs(int index)
+{
+ if (-1 == index)
+ return;
+ for (int i = count() - 1; i > index; --i)
+ closeTab(i);
+ for (int i = index - 1; i >= 0; --i)
+ closeTab(i);
+}
+
+// When index is -1 index chooses the current tab
+void TabWidget::cloneTab(int index)
+{
+ if (index < 0)
+ index = currentIndex();
+ if (index < 0 || index >= count())
+ return;
+ WebView *tab = newTab(false);
+ tab->setUrl(webView(index)->url());
+}
+
+// When index is -1 index chooses the current tab
+void TabWidget::closeTab(int index)
+{
+ if (index < 0)
+ index = currentIndex();
+ if (index < 0 || index >= count())
+ return;
+
+ bool hasFocus = false;
+ if (WebView *tab = webView(index)) {
+ if (tab->isModified()) {
+ QMessageBox closeConfirmation(tab);
+ closeConfirmation.setWindowFlags(Qt::Sheet);
+ closeConfirmation.setWindowTitle(tr("Do you really want to close this page?"));
+ closeConfirmation.setInformativeText(tr("You have modified this page and when closing it you would lose the modification.\n"
+ "Do you really want to close this page?\n"));
+ closeConfirmation.setIcon(QMessageBox::Question);
+ closeConfirmation.addButton(QMessageBox::Yes);
+ closeConfirmation.addButton(QMessageBox::No);
+ closeConfirmation.setEscapeButton(QMessageBox::No);
+ if (closeConfirmation.exec() == QMessageBox::No)
+ return;
+ }
+ hasFocus = tab->hasFocus();
+
+ m_recentlyClosedTabsAction->setEnabled(true);
+ m_recentlyClosedTabs.prepend(tab->url());
+ if (m_recentlyClosedTabs.size() >= TabWidget::m_recentlyClosedTabsSize)
+ m_recentlyClosedTabs.removeLast();
+ }
+ QWidget *lineEdit = m_lineEdits->widget(index);
+ m_lineEdits->removeWidget(lineEdit);
+ lineEdit->deleteLater();
+ QWidget *webView = widget(index);
+ removeTab(index);
+ webView->deleteLater();
+ emit tabsChanged();
+ if (hasFocus && count() > 0)
+ currentWebView()->setFocus();
+ if (count() == 0)
+ emit lastTabClosed();
+}
+
+void TabWidget::webViewLoadStarted()
+{
+ WebView *webView = qobject_cast<WebView*>(sender());
+ int index = webViewIndex(webView);
+ if (-1 != index) {
+ QIcon icon(QLatin1String(":loading.gif"));
+ setTabIcon(index, icon);
+ }
+}
+
+void TabWidget::webViewIconChanged()
+{
+ WebView *webView = qobject_cast<WebView*>(sender());
+ int index = webViewIndex(webView);
+ if (-1 != index) {
+ QIcon icon = BrowserApplication::instance()->icon(webView->url());
+ setTabIcon(index, icon);
+ }
+}
+
+void TabWidget::webViewTitleChanged(const QString &title)
+{
+ WebView *webView = qobject_cast<WebView*>(sender());
+ int index = webViewIndex(webView);
+ if (-1 != index) {
+ setTabText(index, title);
+ }
+ if (currentIndex() == index)
+ emit setCurrentTitle(title);
+ BrowserApplication::historyManager()->updateHistoryItem(webView->url(), title);
+}
+
+void TabWidget::webViewUrlChanged(const QUrl &url)
+{
+ WebView *webView = qobject_cast<WebView*>(sender());
+ int index = webViewIndex(webView);
+ if (-1 != index) {
+ m_tabBar->setTabData(index, url);
+ }
+ emit tabsChanged();
+}
+
+void TabWidget::aboutToShowRecentTabsMenu()
+{
+ m_recentlyClosedTabsMenu->clear();
+ for (int i = 0; i < m_recentlyClosedTabs.count(); ++i) {
+ QAction *action = new QAction(m_recentlyClosedTabsMenu);
+ action->setData(m_recentlyClosedTabs.at(i));
+ QIcon icon = BrowserApplication::instance()->icon(m_recentlyClosedTabs.at(i));
+ action->setIcon(icon);
+ action->setText(m_recentlyClosedTabs.at(i).toString());
+ m_recentlyClosedTabsMenu->addAction(action);
+ }
+}
+
+void TabWidget::aboutToShowRecentTriggeredAction(QAction *action)
+{
+ QUrl url = action->data().toUrl();
+ loadUrlInCurrentTab(url);
+}
+
+void TabWidget::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ if (!childAt(event->pos())
+ // Remove the line below when QTabWidget does not have a one pixel frame
+ && event->pos().y() < (tabBar()->y() + tabBar()->height())) {
+ newTab();
+ return;
+ }
+ QTabWidget::mouseDoubleClickEvent(event);
+}
+
+void TabWidget::contextMenuEvent(QContextMenuEvent *event)
+{
+ if (!childAt(event->pos())) {
+ m_tabBar->contextMenuRequested(event->pos());
+ return;
+ }
+ QTabWidget::contextMenuEvent(event);
+}
+
+void TabWidget::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::MidButton && !childAt(event->pos())
+ // Remove the line below when QTabWidget does not have a one pixel frame
+ && event->pos().y() < (tabBar()->y() + tabBar()->height())) {
+ QUrl url(QApplication::clipboard()->text(QClipboard::Selection));
+ if (!url.isEmpty() && url.isValid() && !url.scheme().isEmpty()) {
+ WebView *webView = newTab();
+ webView->setUrl(url);
+ }
+ }
+}
+
+void TabWidget::loadUrlInCurrentTab(const QUrl &url)
+{
+ WebView *webView = currentWebView();
+ if (webView) {
+ webView->loadUrl(url);
+ webView->setFocus();
+ }
+}
+
+void TabWidget::nextTab()
+{
+ int next = currentIndex() + 1;
+ if (next == count())
+ next = 0;
+ setCurrentIndex(next);
+}
+
+void TabWidget::previousTab()
+{
+ int next = currentIndex() - 1;
+ if (next < 0)
+ next = count() - 1;
+ setCurrentIndex(next);
+}
+
+static const qint32 TabWidgetMagic = 0xaa;
+
+QByteArray TabWidget::saveState() const
+{
+ int version = 1;
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+
+ stream << qint32(TabWidgetMagic);
+ stream << qint32(version);
+
+ QStringList tabs;
+ for (int i = 0; i < count(); ++i) {
+ if (WebView *tab = qobject_cast<WebView*>(widget(i))) {
+ tabs.append(tab->url().toString());
+ } else {
+ tabs.append(QString::null);
+ }
+ }
+ stream << tabs;
+ stream << currentIndex();
+ return data;
+}
+
+bool TabWidget::restoreState(const QByteArray &state)
+{
+ int version = 1;
+ QByteArray sd = state;
+ QDataStream stream(&sd, QIODevice::ReadOnly);
+ if (stream.atEnd())
+ return false;
+
+ qint32 marker;
+ qint32 v;
+ stream >> marker;
+ stream >> v;
+ if (marker != TabWidgetMagic || v != version)
+ return false;
+
+ QStringList openTabs;
+ stream >> openTabs;
+
+ for (int i = 0; i < openTabs.count(); ++i) {
+ if (i != 0)
+ newTab();
+ loadPage(openTabs.at(i));
+ }
+
+ int currentTab;
+ stream >> currentTab;
+ setCurrentIndex(currentTab);
+
+ return true;
+}
+
+WebActionMapper::WebActionMapper(QAction *root, QWebPage::WebAction webAction, QObject *parent)
+ : QObject(parent)
+ , m_currentParent(0)
+ , m_root(root)
+ , m_webAction(webAction)
+{
+ if (!m_root)
+ return;
+ connect(m_root, SIGNAL(triggered()), this, SLOT(rootTriggered()));
+ connect(root, SIGNAL(destroyed(QObject *)), this, SLOT(rootDestroyed()));
+ root->setEnabled(false);
+}
+
+void WebActionMapper::rootDestroyed()
+{
+ m_root = 0;
+}
+
+void WebActionMapper::currentDestroyed()
+{
+ updateCurrent(0);
+}
+
+void WebActionMapper::addChild(QAction *action)
+{
+ if (!action)
+ return;
+ connect(action, SIGNAL(changed()), this, SLOT(childChanged()));
+}
+
+QWebPage::WebAction WebActionMapper::webAction() const
+{
+ return m_webAction;
+}
+
+void WebActionMapper::rootTriggered()
+{
+ if (m_currentParent) {
+ QAction *gotoAction = m_currentParent->action(m_webAction);
+ gotoAction->trigger();
+ }
+}
+
+void WebActionMapper::childChanged()
+{
+ if (QAction *source = qobject_cast<QAction*>(sender())) {
+ if (m_root
+ && m_currentParent
+ && source->parent() == m_currentParent) {
+ m_root->setChecked(source->isChecked());
+ m_root->setEnabled(source->isEnabled());
+ }
+ }
+}
+
+void WebActionMapper::updateCurrent(QWebPage *currentParent)
+{
+ if (m_currentParent)
+ disconnect(m_currentParent, SIGNAL(destroyed(QObject *)),
+ this, SLOT(currentDestroyed()));
+
+ m_currentParent = currentParent;
+ if (!m_root)
+ return;
+ if (!m_currentParent) {
+ m_root->setEnabled(false);
+ m_root->setChecked(false);
+ return;
+ }
+ QAction *source = m_currentParent->action(m_webAction);
+ m_root->setChecked(source->isChecked());
+ m_root->setEnabled(source->isEnabled());
+ connect(m_currentParent, SIGNAL(destroyed(QObject *)),
+ this, SLOT(currentDestroyed()));
+}
+
diff --git a/demos/browser/tabwidget.h b/demos/browser/tabwidget.h
new file mode 100644
index 0000000..da3fe42
--- /dev/null
+++ b/demos/browser/tabwidget.h
@@ -0,0 +1,224 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TABWIDGET_H
+#define TABWIDGET_H
+
+#include <QtGui/QTabBar>
+
+#include <QtGui/QShortcut>
+/*
+ Tab bar with a few more features such as a context menu and shortcuts
+ */
+class TabBar : public QTabBar
+{
+ Q_OBJECT
+
+signals:
+ void newTab();
+ void cloneTab(int index);
+ void closeTab(int index);
+ void closeOtherTabs(int index);
+ void reloadTab(int index);
+ void reloadAllTabs();
+ void tabMoveRequested(int fromIndex, int toIndex);
+
+public:
+ TabBar(QWidget *parent = 0);
+
+protected:
+ void mousePressEvent(QMouseEvent* event);
+ void mouseMoveEvent(QMouseEvent* event);
+
+private slots:
+ void selectTabAction();
+ void cloneTab();
+ void closeTab();
+ void closeOtherTabs();
+ void reloadTab();
+ void contextMenuRequested(const QPoint &position);
+
+private:
+ QList<QShortcut*> m_tabShortcuts;
+ friend class TabWidget;
+
+ QPoint m_dragStartPos;
+ int m_dragCurrentIndex;
+};
+
+#include <QtWebKit/QWebPage>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+QT_END_NAMESPACE
+class WebView;
+/*!
+ A proxy object that connects a single browser action
+ to one child webpage action at a time.
+
+ Example usage: used to keep the main window stop action in sync with
+ the current tabs webview's stop action.
+ */
+class WebActionMapper : public QObject
+{
+ Q_OBJECT
+
+public:
+ WebActionMapper(QAction *root, QWebPage::WebAction webAction, QObject *parent);
+ QWebPage::WebAction webAction() const;
+ void addChild(QAction *action);
+ void updateCurrent(QWebPage *currentParent);
+
+private slots:
+ void rootTriggered();
+ void childChanged();
+ void rootDestroyed();
+ void currentDestroyed();
+
+private:
+ QWebPage *m_currentParent;
+ QAction *m_root;
+ QWebPage::WebAction m_webAction;
+};
+
+#include <QtCore/QUrl>
+#include <QtGui/QTabWidget>
+QT_BEGIN_NAMESPACE
+class QCompleter;
+class QLineEdit;
+class QMenu;
+class QStackedWidget;
+QT_END_NAMESPACE
+/*!
+ TabWidget that contains WebViews and a stack widget of associated line edits.
+
+ Connects up the current tab's signals to this class's signal and uses WebActionMapper
+ to proxy the actions.
+ */
+class TabWidget : public QTabWidget
+{
+ Q_OBJECT
+
+signals:
+ // tab widget signals
+ void loadPage(const QString &url);
+ void tabsChanged();
+ void lastTabClosed();
+
+ // current tab signals
+ void setCurrentTitle(const QString &url);
+ void showStatusBarMessage(const QString &message);
+ void linkHovered(const QString &link);
+ void loadProgress(int progress);
+ void geometryChangeRequested(const QRect &geometry);
+ void menuBarVisibilityChangeRequested(bool visible);
+ void statusBarVisibilityChangeRequested(bool visible);
+ void toolBarVisibilityChangeRequested(bool visible);
+ void printRequested(QWebFrame *frame);
+
+public:
+ TabWidget(QWidget *parent = 0);
+ void clear();
+ void addWebAction(QAction *action, QWebPage::WebAction webAction);
+
+ QAction *newTabAction() const;
+ QAction *closeTabAction() const;
+ QAction *recentlyClosedTabsAction() const;
+ QAction *nextTabAction() const;
+ QAction *previousTabAction() const;
+
+ QWidget *lineEditStack() const;
+ QLineEdit *currentLineEdit() const;
+ WebView *currentWebView() const;
+ WebView *webView(int index) const;
+ QLineEdit *lineEdit(int index) const;
+ int webViewIndex(WebView *webView) const;
+
+ QByteArray saveState() const;
+ bool restoreState(const QByteArray &state);
+
+protected:
+ void mouseDoubleClickEvent(QMouseEvent *event);
+ void contextMenuEvent(QContextMenuEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+
+public slots:
+ void loadUrlInCurrentTab(const QUrl &url);
+ WebView *newTab(bool makeCurrent = true);
+ void cloneTab(int index = -1);
+ void closeTab(int index = -1);
+ void closeOtherTabs(int index);
+ void reloadTab(int index = -1);
+ void reloadAllTabs();
+ void nextTab();
+ void previousTab();
+
+private slots:
+ void currentChanged(int index);
+ void aboutToShowRecentTabsMenu();
+ void aboutToShowRecentTriggeredAction(QAction *action);
+ void webViewLoadStarted();
+ void webViewIconChanged();
+ void webViewTitleChanged(const QString &title);
+ void webViewUrlChanged(const QUrl &url);
+ void lineEditReturnPressed();
+ void windowCloseRequested();
+ void moveTab(int fromIndex, int toIndex);
+
+private:
+ QAction *m_recentlyClosedTabsAction;
+ QAction *m_newTabAction;
+ QAction *m_closeTabAction;
+ QAction *m_nextTabAction;
+ QAction *m_previousTabAction;
+
+ QMenu *m_recentlyClosedTabsMenu;
+ static const int m_recentlyClosedTabsSize = 10;
+ QList<QUrl> m_recentlyClosedTabs;
+ QList<WebActionMapper*> m_actions;
+
+ QCompleter *m_lineEditCompleter;
+ QStackedWidget *m_lineEdits;
+ TabBar *m_tabBar;
+};
+
+#endif // TABWIDGET_H
+
diff --git a/demos/browser/toolbarsearch.cpp b/demos/browser/toolbarsearch.cpp
new file mode 100644
index 0000000..255b5e9
--- /dev/null
+++ b/demos/browser/toolbarsearch.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "toolbarsearch.h"
+#include "autosaver.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QUrl>
+
+#include <QtGui/QCompleter>
+#include <QtGui/QMenu>
+#include <QtGui/QStringListModel>
+
+#include <QtWebKit/QWebSettings>
+
+/*
+ ToolbarSearch is a very basic search widget that also contains a small history.
+ Searches are turned into urls that use Google to perform search
+ */
+ToolbarSearch::ToolbarSearch(QWidget *parent)
+ : SearchLineEdit(parent)
+ , m_autosaver(new AutoSaver(this))
+ , m_maxSavedSearches(10)
+ , m_stringListModel(new QStringListModel(this))
+{
+ QMenu *m = menu();
+ connect(m, SIGNAL(aboutToShow()), this, SLOT(aboutToShowMenu()));
+ connect(m, SIGNAL(triggered(QAction*)), this, SLOT(triggeredMenuAction(QAction*)));
+
+ QCompleter *completer = new QCompleter(m_stringListModel, this);
+ completer->setCompletionMode(QCompleter::InlineCompletion);
+ lineEdit()->setCompleter(completer);
+
+ connect(lineEdit(), SIGNAL(returnPressed()), SLOT(searchNow()));
+ setInactiveText(tr("Google"));
+ load();
+}
+
+ToolbarSearch::~ToolbarSearch()
+{
+ m_autosaver->saveIfNeccessary();
+}
+
+void ToolbarSearch::save()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("toolbarsearch"));
+ settings.setValue(QLatin1String("recentSearches"), m_stringListModel->stringList());
+ settings.setValue(QLatin1String("maximumSaved"), m_maxSavedSearches);
+ settings.endGroup();
+}
+
+void ToolbarSearch::load()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("toolbarsearch"));
+ QStringList list = settings.value(QLatin1String("recentSearches")).toStringList();
+ m_maxSavedSearches = settings.value(QLatin1String("maximumSaved"), m_maxSavedSearches).toInt();
+ m_stringListModel->setStringList(list);
+ settings.endGroup();
+}
+
+void ToolbarSearch::searchNow()
+{
+ QString searchText = lineEdit()->text();
+ QStringList newList = m_stringListModel->stringList();
+ if (newList.contains(searchText))
+ newList.removeAt(newList.indexOf(searchText));
+ newList.prepend(searchText);
+ if (newList.size() >= m_maxSavedSearches)
+ newList.removeLast();
+
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (!globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) {
+ m_stringListModel->setStringList(newList);
+ m_autosaver->changeOccurred();
+ }
+
+ QUrl url(QLatin1String("http://www.google.com/search"));
+ url.addQueryItem(QLatin1String("q"), searchText);
+ url.addQueryItem(QLatin1String("ie"), QLatin1String("UTF-8"));
+ url.addQueryItem(QLatin1String("oe"), QLatin1String("UTF-8"));
+ url.addQueryItem(QLatin1String("client"), QLatin1String("qtdemobrowser"));
+ emit search(url);
+}
+
+void ToolbarSearch::aboutToShowMenu()
+{
+ lineEdit()->selectAll();
+ QMenu *m = menu();
+ m->clear();
+ QStringList list = m_stringListModel->stringList();
+ if (list.isEmpty()) {
+ m->addAction(tr("No Recent Searches"));
+ return;
+ }
+
+ QAction *recent = m->addAction(tr("Recent Searches"));
+ recent->setEnabled(false);
+ for (int i = 0; i < list.count(); ++i) {
+ QString text = list.at(i);
+ m->addAction(text)->setData(text);
+ }
+ m->addSeparator();
+ m->addAction(tr("Clear Recent Searches"), this, SLOT(clear()));
+}
+
+void ToolbarSearch::triggeredMenuAction(QAction *action)
+{
+ QVariant v = action->data();
+ if (v.canConvert<QString>()) {
+ QString text = v.toString();
+ lineEdit()->setText(text);
+ searchNow();
+ }
+}
+
+void ToolbarSearch::clear()
+{
+ m_stringListModel->setStringList(QStringList());
+ m_autosaver->changeOccurred();;
+}
+
diff --git a/demos/browser/toolbarsearch.h b/demos/browser/toolbarsearch.h
new file mode 100644
index 0000000..8e1be8d
--- /dev/null
+++ b/demos/browser/toolbarsearch.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TOOLBARSEARCH_H
+#define TOOLBARSEARCH_H
+
+#include "searchlineedit.h"
+
+QT_BEGIN_NAMESPACE
+class QUrl;
+class QAction;
+class QStringListModel;
+QT_END_NAMESPACE
+
+class AutoSaver;
+
+class ToolbarSearch : public SearchLineEdit
+{
+ Q_OBJECT
+
+signals:
+ void search(const QUrl &url);
+
+public:
+ ToolbarSearch(QWidget *parent = 0);
+ ~ToolbarSearch();
+
+public slots:
+ void clear();
+ void searchNow();
+
+private slots:
+ void save();
+ void aboutToShowMenu();
+ void triggeredMenuAction(QAction *action);
+
+private:
+ void load();
+
+ AutoSaver *m_autosaver;
+ int m_maxSavedSearches;
+ QStringListModel *m_stringListModel;
+};
+
+#endif // TOOLBARSEARCH_H
+
diff --git a/demos/browser/urllineedit.cpp b/demos/browser/urllineedit.cpp
new file mode 100644
index 0000000..f7a6345
--- /dev/null
+++ b/demos/browser/urllineedit.cpp
@@ -0,0 +1,340 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "urllineedit.h"
+
+#include "browserapplication.h"
+#include "searchlineedit.h"
+#include "webview.h"
+
+#include <QtCore/QEvent>
+
+#include <QtGui/QApplication>
+#include <QtGui/QCompleter>
+#include <QtGui/QFocusEvent>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QPainter>
+#include <QtGui/QStyle>
+#include <QtGui/QStyleOptionFrameV2>
+
+#include <QtCore/QDebug>
+
+ExLineEdit::ExLineEdit(QWidget *parent)
+ : QWidget(parent)
+ , m_leftWidget(0)
+ , m_lineEdit(new QLineEdit(this))
+ , m_clearButton(0)
+{
+ setFocusPolicy(m_lineEdit->focusPolicy());
+ setAttribute(Qt::WA_InputMethodEnabled);
+ setSizePolicy(m_lineEdit->sizePolicy());
+ setBackgroundRole(m_lineEdit->backgroundRole());
+ setMouseTracking(true);
+ setAcceptDrops(true);
+ setAttribute(Qt::WA_MacShowFocusRect, true);
+ QPalette p = m_lineEdit->palette();
+ setPalette(p);
+
+ // line edit
+ m_lineEdit->setFrame(false);
+ m_lineEdit->setFocusProxy(this);
+ m_lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false);
+ QPalette clearPalette = m_lineEdit->palette();
+ clearPalette.setBrush(QPalette::Base, QBrush(Qt::transparent));
+ m_lineEdit->setPalette(clearPalette);
+
+ // clearButton
+ m_clearButton = new ClearButton(this);
+ connect(m_clearButton, SIGNAL(clicked()),
+ m_lineEdit, SLOT(clear()));
+ connect(m_lineEdit, SIGNAL(textChanged(const QString&)),
+ m_clearButton, SLOT(textChanged(const QString&)));
+}
+
+void ExLineEdit::setLeftWidget(QWidget *widget)
+{
+ m_leftWidget = widget;
+}
+
+QWidget *ExLineEdit::leftWidget() const
+{
+ return m_leftWidget;
+}
+
+void ExLineEdit::resizeEvent(QResizeEvent *event)
+{
+ Q_ASSERT(m_leftWidget);
+ updateGeometries();
+ QWidget::resizeEvent(event);
+}
+
+void ExLineEdit::updateGeometries()
+{
+ QStyleOptionFrameV2 panel;
+ initStyleOption(&panel);
+ QRect rect = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
+
+ int height = rect.height();
+ int width = rect.width();
+
+ int m_leftWidgetHeight = m_leftWidget->height();
+ m_leftWidget->setGeometry(rect.x() + 2, rect.y() + (height - m_leftWidgetHeight)/2,
+ m_leftWidget->width(), m_leftWidget->height());
+
+ int clearButtonWidth = this->height();
+ m_lineEdit->setGeometry(m_leftWidget->x() + m_leftWidget->width(), 0,
+ width - clearButtonWidth - m_leftWidget->width(), this->height());
+
+ m_clearButton->setGeometry(this->width() - clearButtonWidth, 0,
+ clearButtonWidth, this->height());
+}
+
+void ExLineEdit::initStyleOption(QStyleOptionFrameV2 *option) const
+{
+ option->initFrom(this);
+ option->rect = contentsRect();
+ option->lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, option, this);
+ option->midLineWidth = 0;
+ option->state |= QStyle::State_Sunken;
+ if (m_lineEdit->isReadOnly())
+ option->state |= QStyle::State_ReadOnly;
+#ifdef QT_KEYPAD_NAVIGATION
+ if (hasEditFocus())
+ option->state |= QStyle::State_HasEditFocus;
+#endif
+ option->features = QStyleOptionFrameV2::None;
+}
+
+QSize ExLineEdit::sizeHint() const
+{
+ m_lineEdit->setFrame(true);
+ QSize size = m_lineEdit->sizeHint();
+ m_lineEdit->setFrame(false);
+ return size;
+}
+
+void ExLineEdit::focusInEvent(QFocusEvent *event)
+{
+ m_lineEdit->event(event);
+ QWidget::focusInEvent(event);
+}
+
+void ExLineEdit::focusOutEvent(QFocusEvent *event)
+{
+ m_lineEdit->event(event);
+
+ if (m_lineEdit->completer()) {
+ connect(m_lineEdit->completer(), SIGNAL(activated(QString)),
+ m_lineEdit, SLOT(setText(QString)));
+ connect(m_lineEdit->completer(), SIGNAL(highlighted(QString)),
+ m_lineEdit, SLOT(_q_completionHighlighted(QString)));
+ }
+ QWidget::focusOutEvent(event);
+}
+
+void ExLineEdit::keyPressEvent(QKeyEvent *event)
+{
+ m_lineEdit->event(event);
+}
+
+bool ExLineEdit::event(QEvent *event)
+{
+ if (event->type() == QEvent::ShortcutOverride)
+ return m_lineEdit->event(event);
+ return QWidget::event(event);
+}
+
+void ExLineEdit::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ QStyleOptionFrameV2 panel;
+ initStyleOption(&panel);
+ style()->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, &p, this);
+}
+
+QVariant ExLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ return m_lineEdit->inputMethodQuery(property);
+}
+
+void ExLineEdit::inputMethodEvent(QInputMethodEvent *e)
+{
+ m_lineEdit->event(e);
+}
+
+
+class UrlIconLabel : public QLabel
+{
+
+public:
+ UrlIconLabel(QWidget *parent);
+
+ WebView *m_webView;
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+
+private:
+ QPoint m_dragStartPos;
+
+};
+
+UrlIconLabel::UrlIconLabel(QWidget *parent)
+ : QLabel(parent)
+ , m_webView(0)
+{
+ setMinimumWidth(16);
+ setMinimumHeight(16);
+}
+
+void UrlIconLabel::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton)
+ m_dragStartPos = event->pos();
+ QLabel::mousePressEvent(event);
+}
+
+void UrlIconLabel::mouseMoveEvent(QMouseEvent *event)
+{
+ if (event->buttons() == Qt::LeftButton
+ && (event->pos() - m_dragStartPos).manhattanLength() > QApplication::startDragDistance()
+ && m_webView) {
+ QDrag *drag = new QDrag(this);
+ QMimeData *mimeData = new QMimeData;
+ mimeData->setText(QString::fromUtf8(m_webView->url().toEncoded()));
+ QList<QUrl> urls;
+ urls.append(m_webView->url());
+ mimeData->setUrls(urls);
+ drag->setMimeData(mimeData);
+ drag->exec();
+ }
+}
+
+UrlLineEdit::UrlLineEdit(QWidget *parent)
+ : ExLineEdit(parent)
+ , m_webView(0)
+ , m_iconLabel(0)
+{
+ // icon
+ m_iconLabel = new UrlIconLabel(this);
+ m_iconLabel->resize(16, 16);
+ setLeftWidget(m_iconLabel);
+ m_defaultBaseColor = palette().color(QPalette::Base);
+
+ webViewIconChanged();
+}
+
+void UrlLineEdit::setWebView(WebView *webView)
+{
+ Q_ASSERT(!m_webView);
+ m_webView = webView;
+ m_iconLabel->m_webView = webView;
+ connect(webView, SIGNAL(urlChanged(const QUrl &)),
+ this, SLOT(webViewUrlChanged(const QUrl &)));
+ connect(webView, SIGNAL(loadFinished(bool)),
+ this, SLOT(webViewIconChanged()));
+ connect(webView, SIGNAL(iconChanged()),
+ this, SLOT(webViewIconChanged()));
+ connect(webView, SIGNAL(loadProgress(int)),
+ this, SLOT(update()));
+}
+
+void UrlLineEdit::webViewUrlChanged(const QUrl &url)
+{
+ m_lineEdit->setText(QString::fromUtf8(url.toEncoded()));
+ m_lineEdit->setCursorPosition(0);
+}
+
+void UrlLineEdit::webViewIconChanged()
+{
+ QUrl url = (m_webView) ? m_webView->url() : QUrl();
+ QIcon icon = BrowserApplication::instance()->icon(url);
+ QPixmap pixmap(icon.pixmap(16, 16));
+ m_iconLabel->setPixmap(pixmap);
+}
+
+QLinearGradient UrlLineEdit::generateGradient(const QColor &color) const
+{
+ QLinearGradient gradient(0, 0, 0, height());
+ gradient.setColorAt(0, m_defaultBaseColor);
+ gradient.setColorAt(0.15, color.lighter(120));
+ gradient.setColorAt(0.5, color);
+ gradient.setColorAt(0.85, color.lighter(120));
+ gradient.setColorAt(1, m_defaultBaseColor);
+ return gradient;
+}
+
+void UrlLineEdit::focusOutEvent(QFocusEvent *event)
+{
+ if (m_lineEdit->text().isEmpty() && m_webView)
+ m_lineEdit->setText(QString::fromUtf8(m_webView->url().toEncoded()));
+ ExLineEdit::focusOutEvent(event);
+}
+
+void UrlLineEdit::paintEvent(QPaintEvent *event)
+{
+ QPalette p = palette();
+ if (m_webView && m_webView->url().scheme() == QLatin1String("https")) {
+ QColor lightYellow(248, 248, 210);
+ p.setBrush(QPalette::Base, generateGradient(lightYellow));
+ } else {
+ p.setBrush(QPalette::Base, m_defaultBaseColor);
+ }
+ setPalette(p);
+ ExLineEdit::paintEvent(event);
+
+ QPainter painter(this);
+ QStyleOptionFrameV2 panel;
+ initStyleOption(&panel);
+ QRect backgroundRect = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
+ if (m_webView && !hasFocus()) {
+ int progress = m_webView->progress();
+ QColor loadingColor = QColor(116, 192, 250);
+ painter.setBrush(generateGradient(loadingColor));
+ painter.setPen(Qt::transparent);
+ int mid = backgroundRect.width() / 100 * progress;
+ QRect progressRect(backgroundRect.x(), backgroundRect.y(), mid, backgroundRect.height());
+ painter.drawRect(progressRect);
+ }
+}
diff --git a/demos/browser/urllineedit.h b/demos/browser/urllineedit.h
new file mode 100644
index 0000000..6a718f0
--- /dev/null
+++ b/demos/browser/urllineedit.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef URLLINEEDIT_H
+#define URLLINEEDIT_H
+
+#include <QtCore/QUrl>
+#include <QtGui/QWidget>
+#include <QtGui/QStyleOptionFrame>
+
+QT_BEGIN_NAMESPACE
+class QLineEdit;
+QT_END_NAMESPACE
+
+class ClearButton;
+class ExLineEdit : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ExLineEdit(QWidget *parent = 0);
+
+ inline QLineEdit *lineEdit() const { return m_lineEdit; }
+
+ void setLeftWidget(QWidget *widget);
+ QWidget *leftWidget() const;
+
+ QSize sizeHint() const;
+
+ QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+protected:
+ void focusInEvent(QFocusEvent *event);
+ void focusOutEvent(QFocusEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void paintEvent(QPaintEvent *event);
+ void resizeEvent(QResizeEvent *event);
+ void inputMethodEvent(QInputMethodEvent *e);
+ bool event(QEvent *event);
+
+protected:
+ void updateGeometries();
+ void initStyleOption(QStyleOptionFrameV2 *option) const;
+
+ QWidget *m_leftWidget;
+ QLineEdit *m_lineEdit;
+ ClearButton *m_clearButton;
+};
+
+class UrlIconLabel;
+class WebView;
+class UrlLineEdit : public ExLineEdit
+{
+ Q_OBJECT
+
+public:
+ UrlLineEdit(QWidget *parent = 0);
+ void setWebView(WebView *webView);
+
+protected:
+ void paintEvent(QPaintEvent *event);
+ void focusOutEvent(QFocusEvent *event);
+
+private slots:
+ void webViewUrlChanged(const QUrl &url);
+ void webViewIconChanged();
+
+private:
+ QLinearGradient generateGradient(const QColor &color) const;
+ WebView *m_webView;
+ UrlIconLabel *m_iconLabel;
+ QColor m_defaultBaseColor;
+
+};
+
+
+#endif // URLLINEEDIT_H
+
diff --git a/demos/browser/webview.cpp b/demos/browser/webview.cpp
new file mode 100644
index 0000000..6c4d857
--- /dev/null
+++ b/demos/browser/webview.cpp
@@ -0,0 +1,304 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "browserapplication.h"
+#include "browsermainwindow.h"
+#include "cookiejar.h"
+#include "downloadmanager.h"
+#include "networkaccessmanager.h"
+#include "tabwidget.h"
+#include "webview.h"
+
+#include <QtGui/QClipboard>
+#include <QtGui/QMenu>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMouseEvent>
+
+#include <QtWebKit/QWebHitTestResult>
+
+#include <QtUiTools/QUiLoader>
+
+#include <QtCore/QDebug>
+#include <QtCore/QBuffer>
+
+WebPage::WebPage(QObject *parent)
+ : QWebPage(parent)
+ , m_keyboardModifiers(Qt::NoModifier)
+ , m_pressedButtons(Qt::NoButton)
+ , m_openInNewTab(false)
+{
+ setNetworkAccessManager(BrowserApplication::networkAccessManager());
+ connect(this, SIGNAL(unsupportedContent(QNetworkReply *)),
+ this, SLOT(handleUnsupportedContent(QNetworkReply *)));
+}
+
+BrowserMainWindow *WebPage::mainWindow()
+{
+ QObject *w = this->parent();
+ while (w) {
+ if (BrowserMainWindow *mw = qobject_cast<BrowserMainWindow*>(w))
+ return mw;
+ w = w->parent();
+ }
+ return BrowserApplication::instance()->mainWindow();
+}
+
+bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type)
+{
+ // ctrl open in new tab
+ // ctrl-shift open in new tab and select
+ // ctrl-alt open in new window
+ if (type == QWebPage::NavigationTypeLinkClicked
+ && (m_keyboardModifiers & Qt::ControlModifier
+ || m_pressedButtons == Qt::MidButton)) {
+ bool newWindow = (m_keyboardModifiers & Qt::AltModifier);
+ WebView *webView;
+ if (newWindow) {
+ BrowserApplication::instance()->newMainWindow();
+ BrowserMainWindow *newMainWindow = BrowserApplication::instance()->mainWindow();
+ webView = newMainWindow->currentTab();
+ newMainWindow->raise();
+ newMainWindow->activateWindow();
+ webView->setFocus();
+ } else {
+ bool selectNewTab = (m_keyboardModifiers & Qt::ShiftModifier);
+ webView = mainWindow()->tabWidget()->newTab(selectNewTab);
+ }
+ webView->load(request);
+ m_keyboardModifiers = Qt::NoModifier;
+ m_pressedButtons = Qt::NoButton;
+ return false;
+ }
+ if (frame == mainFrame()) {
+ m_loadingUrl = request.url();
+ emit loadingUrl(m_loadingUrl);
+ }
+ return QWebPage::acceptNavigationRequest(frame, request, type);
+}
+
+QWebPage *WebPage::createWindow(QWebPage::WebWindowType type)
+{
+ Q_UNUSED(type);
+ if (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MidButton)
+ m_openInNewTab = true;
+ if (m_openInNewTab) {
+ m_openInNewTab = false;
+ return mainWindow()->tabWidget()->newTab()->page();
+ }
+ BrowserApplication::instance()->newMainWindow();
+ BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow();
+ return mainWindow->currentTab()->page();
+}
+
+#if !defined(QT_NO_UITOOLS)
+QObject *WebPage::createPlugin(const QString &classId, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues)
+{
+ Q_UNUSED(url);
+ Q_UNUSED(paramNames);
+ Q_UNUSED(paramValues);
+ QUiLoader loader;
+ return loader.createWidget(classId, view());
+}
+#endif // !defined(QT_NO_UITOOLS)
+
+void WebPage::handleUnsupportedContent(QNetworkReply *reply)
+{
+ if (reply->error() == QNetworkReply::NoError) {
+ BrowserApplication::downloadManager()->handleUnsupportedContent(reply);
+ return;
+ }
+
+ QFile file(QLatin1String(":/notfound.html"));
+ bool isOpened = file.open(QIODevice::ReadOnly);
+ Q_ASSERT(isOpened);
+ QString title = tr("Error loading page: %1").arg(reply->url().toString());
+ QString html = QString(QLatin1String(file.readAll()))
+ .arg(title)
+ .arg(reply->errorString())
+ .arg(reply->url().toString());
+
+ QBuffer imageBuffer;
+ imageBuffer.open(QBuffer::ReadWrite);
+ QIcon icon = view()->style()->standardIcon(QStyle::SP_MessageBoxWarning, 0, view());
+ QPixmap pixmap = icon.pixmap(QSize(32,32));
+ if (pixmap.save(&imageBuffer, "PNG")) {
+ html.replace(QLatin1String("IMAGE_BINARY_DATA_HERE"),
+ QString(QLatin1String(imageBuffer.buffer().toBase64())));
+ }
+
+ QList<QWebFrame*> frames;
+ frames.append(mainFrame());
+ while (!frames.isEmpty()) {
+ QWebFrame *frame = frames.takeFirst();
+ if (frame->url() == reply->url()) {
+ frame->setHtml(html, reply->url());
+ return;
+ }
+ QList<QWebFrame *> children = frame->childFrames();
+ foreach(QWebFrame *frame, children)
+ frames.append(frame);
+ }
+ if (m_loadingUrl == reply->url()) {
+ mainFrame()->setHtml(html, reply->url());
+ }
+}
+
+
+WebView::WebView(QWidget* parent)
+ : QWebView(parent)
+ , m_progress(0)
+ , m_page(new WebPage(this))
+{
+ setPage(m_page);
+ connect(page(), SIGNAL(statusBarMessage(const QString&)),
+ SLOT(setStatusBarText(const QString&)));
+ connect(this, SIGNAL(loadProgress(int)),
+ this, SLOT(setProgress(int)));
+ connect(this, SIGNAL(loadFinished(bool)),
+ this, SLOT(loadFinished()));
+ connect(page(), SIGNAL(loadingUrl(const QUrl&)),
+ this, SIGNAL(urlChanged(const QUrl &)));
+ connect(page(), SIGNAL(downloadRequested(const QNetworkRequest &)),
+ this, SLOT(downloadRequested(const QNetworkRequest &)));
+ page()->setForwardUnsupportedContent(true);
+
+}
+
+void WebView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QWebHitTestResult r = page()->mainFrame()->hitTestContent(event->pos());
+ if (!r.linkUrl().isEmpty()) {
+ QMenu menu(this);
+ menu.addAction(pageAction(QWebPage::OpenLinkInNewWindow));
+ menu.addAction(tr("Open in New Tab"), this, SLOT(openLinkInNewTab()));
+ menu.addSeparator();
+ menu.addAction(pageAction(QWebPage::DownloadLinkToDisk));
+ // Add link to bookmarks...
+ menu.addSeparator();
+ menu.addAction(pageAction(QWebPage::CopyLinkToClipboard));
+ if (page()->settings()->testAttribute(QWebSettings::DeveloperExtrasEnabled))
+ menu.addAction(pageAction(QWebPage::InspectElement));
+ menu.exec(mapToGlobal(event->pos()));
+ return;
+ }
+ QWebView::contextMenuEvent(event);
+}
+
+void WebView::wheelEvent(QWheelEvent *event)
+{
+ if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
+ int numDegrees = event->delta() / 8;
+ int numSteps = numDegrees / 15;
+ setTextSizeMultiplier(textSizeMultiplier() + numSteps * 0.1);
+ event->accept();
+ return;
+ }
+ QWebView::wheelEvent(event);
+}
+
+void WebView::openLinkInNewTab()
+{
+ m_page->m_openInNewTab = true;
+ pageAction(QWebPage::OpenLinkInNewWindow)->trigger();
+}
+
+void WebView::setProgress(int progress)
+{
+ m_progress = progress;
+}
+
+void WebView::loadFinished()
+{
+ if (100 != m_progress) {
+ qWarning() << "Recieved finished signal while progress is still:" << progress()
+ << "Url:" << url();
+ }
+ m_progress = 0;
+}
+
+void WebView::loadUrl(const QUrl &url)
+{
+ m_initialUrl = url;
+ load(url);
+}
+
+QString WebView::lastStatusBarText() const
+{
+ return m_statusBarText;
+}
+
+QUrl WebView::url() const
+{
+ QUrl url = QWebView::url();
+ if (!url.isEmpty())
+ return url;
+
+ return m_initialUrl;
+}
+
+void WebView::mousePressEvent(QMouseEvent *event)
+{
+ m_page->m_pressedButtons = event->buttons();
+ m_page->m_keyboardModifiers = event->modifiers();
+ QWebView::mousePressEvent(event);
+}
+
+void WebView::mouseReleaseEvent(QMouseEvent *event)
+{
+ QWebView::mouseReleaseEvent(event);
+ if (!event->isAccepted() && (m_page->m_pressedButtons & Qt::MidButton)) {
+ QUrl url(QApplication::clipboard()->text(QClipboard::Selection));
+ if (!url.isEmpty() && url.isValid() && !url.scheme().isEmpty()) {
+ setUrl(url);
+ }
+ }
+}
+
+void WebView::setStatusBarText(const QString &string)
+{
+ m_statusBarText = string;
+}
+
+void WebView::downloadRequested(const QNetworkRequest &request)
+{
+ BrowserApplication::downloadManager()->download(request);
+}
+
diff --git a/demos/browser/webview.h b/demos/browser/webview.h
new file mode 100644
index 0000000..a41bcf3
--- /dev/null
+++ b/demos/browser/webview.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WEBVIEW_H
+#define WEBVIEW_H
+
+#include <QtWebKit/QWebView>
+
+QT_BEGIN_NAMESPACE
+class QAuthenticator;
+class QMouseEvent;
+class QNetworkProxy;
+class QNetworkReply;
+class QSslError;
+QT_END_NAMESPACE
+
+class BrowserMainWindow;
+class WebPage : public QWebPage {
+ Q_OBJECT
+
+signals:
+ void loadingUrl(const QUrl &url);
+
+public:
+ WebPage(QObject *parent = 0);
+ BrowserMainWindow *mainWindow();
+
+protected:
+ bool acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type);
+ QWebPage *createWindow(QWebPage::WebWindowType type);
+#if !defined(QT_NO_UITOOLS)
+ QObject *createPlugin(const QString &classId, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues);
+#endif
+
+private slots:
+ void handleUnsupportedContent(QNetworkReply *reply);
+
+private:
+ friend class WebView;
+
+ // set the webview mousepressedevent
+ Qt::KeyboardModifiers m_keyboardModifiers;
+ Qt::MouseButtons m_pressedButtons;
+ bool m_openInNewTab;
+ QUrl m_loadingUrl;
+};
+
+class WebView : public QWebView {
+ Q_OBJECT
+
+public:
+ WebView(QWidget *parent = 0);
+ WebPage *webPage() const { return m_page; }
+
+ void loadUrl(const QUrl &url);
+ QUrl url() const;
+
+ QString lastStatusBarText() const;
+ inline int progress() const { return m_progress; }
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void contextMenuEvent(QContextMenuEvent *event);
+ void wheelEvent(QWheelEvent *event);
+
+private slots:
+ void setProgress(int progress);
+ void loadFinished();
+ void setStatusBarText(const QString &string);
+ void downloadRequested(const QNetworkRequest &request);
+ void openLinkInNewTab();
+
+private:
+ QString m_statusBarText;
+ QUrl m_initialUrl;
+ int m_progress;
+ WebPage *m_page;
+};
+
+#endif
diff --git a/demos/browser/xbel.cpp b/demos/browser/xbel.cpp
new file mode 100644
index 0000000..a92b649
--- /dev/null
+++ b/demos/browser/xbel.cpp
@@ -0,0 +1,320 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "xbel.h"
+
+#include <QtCore/QFile>
+
+BookmarkNode::BookmarkNode(BookmarkNode::Type type, BookmarkNode *parent) :
+ expanded(false)
+ , m_parent(parent)
+ , m_type(type)
+{
+ if (parent)
+ parent->add(this);
+}
+
+BookmarkNode::~BookmarkNode()
+{
+ if (m_parent)
+ m_parent->remove(this);
+ qDeleteAll(m_children);
+ m_parent = 0;
+ m_type = BookmarkNode::Root;
+}
+
+bool BookmarkNode::operator==(const BookmarkNode &other)
+{
+ if (url != other.url
+ || title != other.title
+ || desc != other.desc
+ || expanded != other.expanded
+ || m_type != other.m_type
+ || m_children.count() != other.m_children.count())
+ return false;
+
+ for (int i = 0; i < m_children.count(); ++i)
+ if (!((*(m_children[i])) == (*(other.m_children[i]))))
+ return false;
+ return true;
+}
+
+BookmarkNode::Type BookmarkNode::type() const
+{
+ return m_type;
+}
+
+void BookmarkNode::setType(Type type)
+{
+ m_type = type;
+}
+
+QList<BookmarkNode *> BookmarkNode::children() const
+{
+ return m_children;
+}
+
+BookmarkNode *BookmarkNode::parent() const
+{
+ return m_parent;
+}
+
+void BookmarkNode::add(BookmarkNode *child, int offset)
+{
+ Q_ASSERT(child->m_type != Root);
+ if (child->m_parent)
+ child->m_parent->remove(child);
+ child->m_parent = this;
+ if (-1 == offset)
+ offset = m_children.size();
+ m_children.insert(offset, child);
+}
+
+void BookmarkNode::remove(BookmarkNode *child)
+{
+ child->m_parent = 0;
+ m_children.removeAll(child);
+}
+
+
+XbelReader::XbelReader()
+{
+}
+
+BookmarkNode *XbelReader::read(const QString &fileName)
+{
+ QFile file(fileName);
+ if (!file.exists()) {
+ return new BookmarkNode(BookmarkNode::Root);
+ }
+ file.open(QFile::ReadOnly);
+ return read(&file);
+}
+
+BookmarkNode *XbelReader::read(QIODevice *device)
+{
+ BookmarkNode *root = new BookmarkNode(BookmarkNode::Root);
+ setDevice(device);
+ while (!atEnd()) {
+ readNext();
+ if (isStartElement()) {
+ QString version = attributes().value(QLatin1String("version")).toString();
+ if (name() == QLatin1String("xbel")
+ && (version.isEmpty() || version == QLatin1String("1.0"))) {
+ readXBEL(root);
+ } else {
+ raiseError(QObject::tr("The file is not an XBEL version 1.0 file."));
+ }
+ }
+ }
+ return root;
+}
+
+void XbelReader::readXBEL(BookmarkNode *parent)
+{
+ Q_ASSERT(isStartElement() && name() == QLatin1String("xbel"));
+
+ while (!atEnd()) {
+ readNext();
+ if (isEndElement())
+ break;
+
+ if (isStartElement()) {
+ if (name() == QLatin1String("folder"))
+ readFolder(parent);
+ else if (name() == QLatin1String("bookmark"))
+ readBookmarkNode(parent);
+ else if (name() == QLatin1String("separator"))
+ readSeparator(parent);
+ else
+ skipUnknownElement();
+ }
+ }
+}
+
+void XbelReader::readFolder(BookmarkNode *parent)
+{
+ Q_ASSERT(isStartElement() && name() == QLatin1String("folder"));
+
+ BookmarkNode *folder = new BookmarkNode(BookmarkNode::Folder, parent);
+ folder->expanded = (attributes().value(QLatin1String("folded")) == QLatin1String("no"));
+
+ while (!atEnd()) {
+ readNext();
+
+ if (isEndElement())
+ break;
+
+ if (isStartElement()) {
+ if (name() == QLatin1String("title"))
+ readTitle(folder);
+ else if (name() == QLatin1String("desc"))
+ readDescription(folder);
+ else if (name() == QLatin1String("folder"))
+ readFolder(folder);
+ else if (name() == QLatin1String("bookmark"))
+ readBookmarkNode(folder);
+ else if (name() == QLatin1String("separator"))
+ readSeparator(folder);
+ else
+ skipUnknownElement();
+ }
+ }
+}
+
+void XbelReader::readTitle(BookmarkNode *parent)
+{
+ Q_ASSERT(isStartElement() && name() == QLatin1String("title"));
+ parent->title = readElementText();
+}
+
+void XbelReader::readDescription(BookmarkNode *parent)
+{
+ Q_ASSERT(isStartElement() && name() == QLatin1String("desc"));
+ parent->desc = readElementText();
+}
+
+void XbelReader::readSeparator(BookmarkNode *parent)
+{
+ new BookmarkNode(BookmarkNode::Separator, parent);
+ // empty elements have a start and end element
+ readNext();
+}
+
+void XbelReader::readBookmarkNode(BookmarkNode *parent)
+{
+ Q_ASSERT(isStartElement() && name() == QLatin1String("bookmark"));
+ BookmarkNode *bookmark = new BookmarkNode(BookmarkNode::Bookmark, parent);
+ bookmark->url = attributes().value(QLatin1String("href")).toString();
+ while (!atEnd()) {
+ readNext();
+ if (isEndElement())
+ break;
+
+ if (isStartElement()) {
+ if (name() == QLatin1String("title"))
+ readTitle(bookmark);
+ else if (name() == QLatin1String("desc"))
+ readDescription(bookmark);
+ else
+ skipUnknownElement();
+ }
+ }
+ if (bookmark->title.isEmpty())
+ bookmark->title = QObject::tr("Unknown title");
+}
+
+void XbelReader::skipUnknownElement()
+{
+ Q_ASSERT(isStartElement());
+
+ while (!atEnd()) {
+ readNext();
+
+ if (isEndElement())
+ break;
+
+ if (isStartElement())
+ skipUnknownElement();
+ }
+}
+
+
+XbelWriter::XbelWriter()
+{
+ setAutoFormatting(true);
+}
+
+bool XbelWriter::write(const QString &fileName, const BookmarkNode *root)
+{
+ QFile file(fileName);
+ if (!root || !file.open(QFile::WriteOnly))
+ return false;
+ return write(&file, root);
+}
+
+bool XbelWriter::write(QIODevice *device, const BookmarkNode *root)
+{
+ setDevice(device);
+
+ writeStartDocument();
+ writeDTD(QLatin1String("<!DOCTYPE xbel>"));
+ writeStartElement(QLatin1String("xbel"));
+ writeAttribute(QLatin1String("version"), QLatin1String("1.0"));
+ if (root->type() == BookmarkNode::Root) {
+ for (int i = 0; i < root->children().count(); ++i)
+ writeItem(root->children().at(i));
+ } else {
+ writeItem(root);
+ }
+
+ writeEndDocument();
+ return true;
+}
+
+void XbelWriter::writeItem(const BookmarkNode *parent)
+{
+ switch (parent->type()) {
+ case BookmarkNode::Folder:
+ writeStartElement(QLatin1String("folder"));
+ writeAttribute(QLatin1String("folded"), parent->expanded ? QLatin1String("no") : QLatin1String("yes"));
+ writeTextElement(QLatin1String("title"), parent->title);
+ for (int i = 0; i < parent->children().count(); ++i)
+ writeItem(parent->children().at(i));
+ writeEndElement();
+ break;
+ case BookmarkNode::Bookmark:
+ writeStartElement(QLatin1String("bookmark"));
+ if (!parent->url.isEmpty())
+ writeAttribute(QLatin1String("href"), parent->url);
+ writeTextElement(QLatin1String("title"), parent->title);
+ if (!parent->desc.isEmpty())
+ writeAttribute(QLatin1String("desc"), parent->desc);
+ writeEndElement();
+ break;
+ case BookmarkNode::Separator:
+ writeEmptyElement(QLatin1String("separator"));
+ break;
+ default:
+ break;
+ }
+}
+
diff --git a/demos/browser/xbel.h b/demos/browser/xbel.h
new file mode 100644
index 0000000..b736d02
--- /dev/null
+++ b/demos/browser/xbel.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef XBEL_H
+#define XBEL_H
+
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QDateTime>
+
+class BookmarkNode
+{
+public:
+ enum Type {
+ Root,
+ Folder,
+ Bookmark,
+ Separator
+ };
+
+ BookmarkNode(Type type = Root, BookmarkNode *parent = 0);
+ ~BookmarkNode();
+ bool operator==(const BookmarkNode &other);
+
+ Type type() const;
+ void setType(Type type);
+ QList<BookmarkNode *> children() const;
+ BookmarkNode *parent() const;
+
+ void add(BookmarkNode *child, int offset = -1);
+ void remove(BookmarkNode *child);
+
+ QString url;
+ QString title;
+ QString desc;
+ bool expanded;
+
+private:
+ BookmarkNode *m_parent;
+ Type m_type;
+ QList<BookmarkNode *> m_children;
+
+};
+
+class XbelReader : public QXmlStreamReader
+{
+public:
+ XbelReader();
+ BookmarkNode *read(const QString &fileName);
+ BookmarkNode *read(QIODevice *device);
+
+private:
+ void skipUnknownElement();
+ void readXBEL(BookmarkNode *parent);
+ void readTitle(BookmarkNode *parent);
+ void readDescription(BookmarkNode *parent);
+ void readSeparator(BookmarkNode *parent);
+ void readFolder(BookmarkNode *parent);
+ void readBookmarkNode(BookmarkNode *parent);
+};
+
+#include <QtCore/QXmlStreamWriter>
+
+class XbelWriter : public QXmlStreamWriter
+{
+public:
+ XbelWriter();
+ bool write(const QString &fileName, const BookmarkNode *root);
+ bool write(QIODevice *device, const BookmarkNode *root);
+
+private:
+ void writeItem(const BookmarkNode *parent);
+};
+
+#endif // XBEL_H
+
diff --git a/demos/chip/chip.cpp b/demos/chip/chip.cpp
new file mode 100644
index 0000000..c2b22da
--- /dev/null
+++ b/demos/chip/chip.cpp
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "chip.h"
+
+#include <QtGui>
+
+Chip::Chip(const QColor &color, int x, int y)
+{
+ this->x = x;
+ this->y = y;
+ this->color = color;
+ setZValue((x + y) % 2);
+
+ setFlags(ItemIsSelectable | ItemIsMovable);
+ setAcceptsHoverEvents(true);
+}
+
+QRectF Chip::boundingRect() const
+{
+ return QRectF(0, 0, 110, 70);
+}
+
+QPainterPath Chip::shape() const
+{
+ QPainterPath path;
+ path.addRect(14, 14, 82, 42);
+ return path;
+}
+
+void Chip::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(widget);
+
+ QColor fillColor = (option->state & QStyle::State_Selected) ? color.dark(150) : color;
+ if (option->state & QStyle::State_MouseOver)
+ fillColor = fillColor.light(125);
+
+ if (option->levelOfDetail < 0.2) {
+ if (option->levelOfDetail < 0.125) {
+ painter->fillRect(QRectF(0, 0, 110, 70), fillColor);
+ return;
+ }
+
+ QBrush b = painter->brush();
+ painter->setBrush(fillColor);
+ painter->drawRect(13, 13, 97, 57);
+ painter->setBrush(b);
+ return;
+ }
+
+ QPen oldPen = painter->pen();
+ QPen pen = oldPen;
+ int width = 0;
+ if (option->state & QStyle::State_Selected)
+ width += 2;
+
+ pen.setWidth(width);
+ QBrush b = painter->brush();
+ painter->setBrush(QBrush(fillColor.dark(option->state & QStyle::State_Sunken ? 120 : 100)));
+
+ painter->drawRect(QRect(14, 14, 79, 39));
+ painter->setBrush(b);
+
+ if (option->levelOfDetail >= 1) {
+ painter->setPen(QPen(Qt::gray, 1));
+ painter->drawLine(15, 54, 94, 54);
+ painter->drawLine(94, 53, 94, 15);
+ painter->setPen(QPen(Qt::black, 0));
+ }
+
+ // Draw text
+ if (option->levelOfDetail >= 2) {
+ QFont font("Times", 10);
+ font.setStyleStrategy(QFont::ForceOutline);
+ painter->setFont(font);
+ painter->save();
+ painter->scale(0.1, 0.1);
+ painter->drawText(170, 180, QString("Model: VSC-2000 (Very Small Chip) at %1x%2").arg(x).arg(y));
+ painter->drawText(170, 200, QString("Serial number: DLWR-WEER-123L-ZZ33-SDSJ"));
+ painter->drawText(170, 220, QString("Manufacturer: Chip Manufacturer"));
+ painter->restore();
+ }
+
+ // Draw lines
+ QVarLengthArray<QLineF, 36> lines;
+ if (option->levelOfDetail >= 0.5) {
+ for (int i = 0; i <= 10; i += (option->levelOfDetail > 0.5 ? 1 : 2)) {
+ lines.append(QLineF(18 + 7 * i, 13, 18 + 7 * i, 5));
+ lines.append(QLineF(18 + 7 * i, 54, 18 + 7 * i, 62));
+ }
+ for (int i = 0; i <= 6; i += (option->levelOfDetail > 0.5 ? 1 : 2)) {
+ lines.append(QLineF(5, 18 + i * 5, 13, 18 + i * 5));
+ lines.append(QLineF(94, 18 + i * 5, 102, 18 + i * 5));
+ }
+ }
+ if (option->levelOfDetail >= 0.4) {
+ const QLineF lineData[] = {
+ QLineF(25, 35, 35, 35),
+ QLineF(35, 30, 35, 40),
+ QLineF(35, 30, 45, 35),
+ QLineF(35, 40, 45, 35),
+ QLineF(45, 30, 45, 40),
+ QLineF(45, 35, 55, 35)
+ };
+ lines.append(lineData, 6);
+ }
+ painter->drawLines(lines.data(), lines.size());
+
+ // Draw red ink
+ if (stuff.size() > 1) {
+ QPen p = painter->pen();
+ painter->setPen(QPen(Qt::red, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+ painter->setBrush(Qt::NoBrush);
+ QPainterPath path;
+ path.moveTo(stuff.first());
+ for (int i = 1; i < stuff.size(); ++i)
+ path.lineTo(stuff.at(i));
+ painter->drawPath(path);
+ painter->setPen(p);
+ }
+}
+
+void Chip::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ QGraphicsItem::mousePressEvent(event);
+ update();
+}
+
+void Chip::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (event->modifiers() & Qt::ShiftModifier) {
+ stuff << event->pos();
+ update();
+ return;
+ }
+ QGraphicsItem::mouseMoveEvent(event);
+}
+
+void Chip::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ QGraphicsItem::mouseReleaseEvent(event);
+ update();
+}
diff --git a/demos/chip/chip.h b/demos/chip/chip.h
new file mode 100644
index 0000000..9866f80
--- /dev/null
+++ b/demos/chip/chip.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CHIP_H
+#define CHIP_H
+
+#include <QtGui/QColor>
+#include <QtGui/QGraphicsItem>
+
+class Chip : public QGraphicsItem
+{
+public:
+ Chip(const QColor &color, int x, int y);
+
+ QRectF boundingRect() const;
+ QPainterPath shape() const;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget);
+
+protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+
+private:
+ int x, y;
+ QColor color;
+ QList<QPointF> stuff;
+};
+
+#endif
diff --git a/demos/chip/chip.pro b/demos/chip/chip.pro
new file mode 100644
index 0000000..2c44e56
--- /dev/null
+++ b/demos/chip/chip.pro
@@ -0,0 +1,21 @@
+RESOURCES += images.qrc
+
+HEADERS += mainwindow.h view.h chip.h
+SOURCES += main.cpp
+SOURCES += mainwindow.cpp view.cpp chip.cpp
+
+contains(QT_CONFIG, opengl):QT += opengl
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/chip
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.png *.pro *.html *.doc images
+sources.path = $$[QT_INSTALL_DEMOS]/chip
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
diff --git a/demos/chip/fileprint.png b/demos/chip/fileprint.png
new file mode 100644
index 0000000..ba7c02d
--- /dev/null
+++ b/demos/chip/fileprint.png
Binary files differ
diff --git a/demos/chip/images.qrc b/demos/chip/images.qrc
new file mode 100644
index 0000000..c7cdf0c
--- /dev/null
+++ b/demos/chip/images.qrc
@@ -0,0 +1,10 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>qt4logo.png</file>
+ <file>zoomin.png</file>
+ <file>zoomout.png</file>
+ <file>rotateleft.png</file>
+ <file>rotateright.png</file>
+ <file>fileprint.png</file>
+</qresource>
+</RCC>
diff --git a/demos/chip/main.cpp b/demos/chip/main.cpp
new file mode 100644
index 0000000..e945026
--- /dev/null
+++ b/demos/chip/main.cpp
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+
+#include <QApplication>
+
+int main(int argc, char **argv)
+{
+ Q_INIT_RESOURCE(images);
+
+ QApplication app(argc, argv);
+ app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
+
+ MainWindow window;
+ window.show();
+
+ return app.exec();
+}
diff --git a/demos/chip/mainwindow.cpp b/demos/chip/mainwindow.cpp
new file mode 100644
index 0000000..5222cd4
--- /dev/null
+++ b/demos/chip/mainwindow.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+#include "view.h"
+#include "chip.h"
+
+#include <QtGui>
+
+MainWindow::MainWindow(QWidget *parent)
+ : QWidget(parent)
+{
+ populateScene();
+
+ h1Splitter = new QSplitter;
+ h2Splitter = new QSplitter;
+
+ QSplitter *vSplitter = new QSplitter;
+ vSplitter->setOrientation(Qt::Vertical);
+ vSplitter->addWidget(h1Splitter);
+ vSplitter->addWidget(h2Splitter);
+
+ View *view = new View("Top left view");
+ view->view()->setScene(scene);
+ h1Splitter->addWidget(view);
+
+ view = new View("Top right view");
+ view->view()->setScene(scene);
+ h1Splitter->addWidget(view);
+
+ view = new View("Bottom left view");
+ view->view()->setScene(scene);
+ h2Splitter->addWidget(view);
+
+ view = new View("Bottom right view");
+ view->view()->setScene(scene);
+ h2Splitter->addWidget(view);
+
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->addWidget(vSplitter);
+ setLayout(layout);
+
+ setWindowTitle(tr("Chip Demo"));
+}
+
+void MainWindow::populateScene()
+{
+ scene = new QGraphicsScene;
+
+ QImage image(":/qt4logo.png");
+
+ // Populate scene
+ int xx = 0;
+ int nitems = 0;
+ for (int i = -11000; i < 11000; i += 110) {
+ ++xx;
+ int yy = 0;
+ for (int j = -7000; j < 7000; j += 70) {
+ ++yy;
+ qreal x = (i + 11000) / 22000.0;
+ qreal y = (j + 7000) / 14000.0;
+
+ QColor color(image.pixel(int(image.width() * x), int(image.height() * y)));
+ QGraphicsItem *item = new Chip(color, xx, yy);
+ item->setPos(QPointF(i, j));
+ scene->addItem(item);
+
+ ++nitems;
+ }
+ }
+}
diff --git a/demos/chip/mainwindow.h b/demos/chip/mainwindow.h
new file mode 100644
index 0000000..5decca8
--- /dev/null
+++ b/demos/chip/mainwindow.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QtGui/qwidget.h>
+
+QT_FORWARD_DECLARE_CLASS(QGraphicsScene)
+QT_FORWARD_DECLARE_CLASS(QGraphicsView)
+QT_FORWARD_DECLARE_CLASS(QLabel)
+QT_FORWARD_DECLARE_CLASS(QSlider)
+QT_FORWARD_DECLARE_CLASS(QSplitter)
+
+class MainWindow : public QWidget
+{
+ Q_OBJECT
+public:
+ MainWindow(QWidget *parent = 0);
+
+private:
+ void setupMatrix();
+ void populateScene();
+
+ QGraphicsScene *scene;
+ QSplitter *h1Splitter;
+ QSplitter *h2Splitter;
+};
+
+#endif
diff --git a/demos/chip/qt4logo.png b/demos/chip/qt4logo.png
new file mode 100644
index 0000000..157e86e
--- /dev/null
+++ b/demos/chip/qt4logo.png
Binary files differ
diff --git a/demos/chip/rotateleft.png b/demos/chip/rotateleft.png
new file mode 100644
index 0000000..8cfa931
--- /dev/null
+++ b/demos/chip/rotateleft.png
Binary files differ
diff --git a/demos/chip/rotateright.png b/demos/chip/rotateright.png
new file mode 100644
index 0000000..ec5e866
--- /dev/null
+++ b/demos/chip/rotateright.png
Binary files differ
diff --git a/demos/chip/view.cpp b/demos/chip/view.cpp
new file mode 100644
index 0000000..f919af3
--- /dev/null
+++ b/demos/chip/view.cpp
@@ -0,0 +1,234 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "view.h"
+
+#include <QtGui>
+#ifndef QT_NO_OPENGL
+#include <QtOpenGL>
+#endif
+
+#include <qmath.h>
+
+View::View(const QString &name, QWidget *parent)
+ : QFrame(parent)
+{
+ setFrameStyle(Sunken | StyledPanel);
+ graphicsView = new QGraphicsView;
+ graphicsView->setRenderHint(QPainter::Antialiasing, false);
+ graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
+ graphicsView->setOptimizationFlags(QGraphicsView::DontSavePainterState);
+ graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
+
+ int size = style()->pixelMetric(QStyle::PM_ToolBarIconSize);
+ QSize iconSize(size, size);
+
+ QToolButton *zoomInIcon = new QToolButton;
+ zoomInIcon->setAutoRepeat(true);
+ zoomInIcon->setAutoRepeatInterval(33);
+ zoomInIcon->setAutoRepeatDelay(0);
+ zoomInIcon->setIcon(QPixmap(":/zoomin.png"));
+ zoomInIcon->setIconSize(iconSize);
+ QToolButton *zoomOutIcon = new QToolButton;
+ zoomOutIcon->setAutoRepeat(true);
+ zoomOutIcon->setAutoRepeatInterval(33);
+ zoomOutIcon->setAutoRepeatDelay(0);
+ zoomOutIcon->setIcon(QPixmap(":/zoomout.png"));
+ zoomOutIcon->setIconSize(iconSize);
+ zoomSlider = new QSlider;
+ zoomSlider->setMinimum(0);
+ zoomSlider->setMaximum(500);
+ zoomSlider->setValue(250);
+ zoomSlider->setTickPosition(QSlider::TicksRight);
+
+ // Zoom slider layout
+ QVBoxLayout *zoomSliderLayout = new QVBoxLayout;
+ zoomSliderLayout->addWidget(zoomInIcon);
+ zoomSliderLayout->addWidget(zoomSlider);
+ zoomSliderLayout->addWidget(zoomOutIcon);
+
+ QToolButton *rotateLeftIcon = new QToolButton;
+ rotateLeftIcon->setIcon(QPixmap(":/rotateleft.png"));
+ rotateLeftIcon->setIconSize(iconSize);
+ QToolButton *rotateRightIcon = new QToolButton;
+ rotateRightIcon->setIcon(QPixmap(":/rotateright.png"));
+ rotateRightIcon->setIconSize(iconSize);
+ rotateSlider = new QSlider;
+ rotateSlider->setOrientation(Qt::Horizontal);
+ rotateSlider->setMinimum(-360);
+ rotateSlider->setMaximum(360);
+ rotateSlider->setValue(0);
+ rotateSlider->setTickPosition(QSlider::TicksBelow);
+
+ // Rotate slider layout
+ QHBoxLayout *rotateSliderLayout = new QHBoxLayout;
+ rotateSliderLayout->addWidget(rotateLeftIcon);
+ rotateSliderLayout->addWidget(rotateSlider);
+ rotateSliderLayout->addWidget(rotateRightIcon);
+
+ resetButton = new QToolButton;
+ resetButton->setText(tr("0"));
+ resetButton->setEnabled(false);
+
+ // Label layout
+ QHBoxLayout *labelLayout = new QHBoxLayout;
+ label = new QLabel(name);
+ antialiasButton = new QToolButton;
+ antialiasButton->setText(tr("Antialiasing"));
+ antialiasButton->setCheckable(true);
+ antialiasButton->setChecked(false);
+ openGlButton = new QToolButton;
+ openGlButton->setText(tr("OpenGL"));
+ openGlButton->setCheckable(true);
+#ifndef QT_NO_OPENGL
+ openGlButton->setEnabled(QGLFormat::hasOpenGL());
+#else
+ openGlButton->setEnabled(false);
+#endif
+ printButton = new QToolButton;
+ printButton->setIcon(QIcon(QPixmap(":/fileprint.png")));
+
+ labelLayout->addWidget(label);
+ labelLayout->addStretch();
+ labelLayout->addWidget(antialiasButton);
+ labelLayout->addWidget(openGlButton);
+ labelLayout->addWidget(printButton);
+
+ QGridLayout *topLayout = new QGridLayout;
+ topLayout->addLayout(labelLayout, 0, 0);
+ topLayout->addWidget(graphicsView, 1, 0);
+ topLayout->addLayout(zoomSliderLayout, 1, 1);
+ topLayout->addLayout(rotateSliderLayout, 2, 0);
+ topLayout->addWidget(resetButton, 2, 1);
+ setLayout(topLayout);
+
+ connect(resetButton, SIGNAL(clicked()), this, SLOT(resetView()));
+ connect(zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(setupMatrix()));
+ connect(rotateSlider, SIGNAL(valueChanged(int)), this, SLOT(setupMatrix()));
+ connect(graphicsView->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(setResetButtonEnabled()));
+ connect(graphicsView->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(setResetButtonEnabled()));
+ connect(antialiasButton, SIGNAL(toggled(bool)), this, SLOT(toggleAntialiasing()));
+ connect(openGlButton, SIGNAL(toggled(bool)), this, SLOT(toggleOpenGL()));
+ connect(rotateLeftIcon, SIGNAL(clicked()), this, SLOT(rotateLeft()));
+ connect(rotateRightIcon, SIGNAL(clicked()), this, SLOT(rotateRight()));
+ connect(zoomInIcon, SIGNAL(clicked()), this, SLOT(zoomIn()));
+ connect(zoomOutIcon, SIGNAL(clicked()), this, SLOT(zoomOut()));
+ connect(printButton, SIGNAL(clicked()), this, SLOT(print()));
+
+ setupMatrix();
+}
+
+QGraphicsView *View::view() const
+{
+ return graphicsView;
+}
+
+void View::resetView()
+{
+ zoomSlider->setValue(250);
+ rotateSlider->setValue(0);
+ setupMatrix();
+ graphicsView->ensureVisible(QRectF(0, 0, 0, 0));
+
+ resetButton->setEnabled(false);
+}
+
+void View::setResetButtonEnabled()
+{
+ resetButton->setEnabled(true);
+}
+
+void View::setupMatrix()
+{
+ qreal scale = qPow(qreal(2), (zoomSlider->value() - 250) / qreal(50));
+
+ QMatrix matrix;
+ matrix.scale(scale, scale);
+ matrix.rotate(rotateSlider->value());
+
+ graphicsView->setMatrix(matrix);
+ setResetButtonEnabled();
+}
+
+void View::toggleOpenGL()
+{
+#ifndef QT_NO_OPENGL
+ graphicsView->setViewport(openGlButton->isChecked() ? new QGLWidget(QGLFormat(QGL::SampleBuffers)) : new QWidget);
+#endif
+}
+
+void View::toggleAntialiasing()
+{
+ graphicsView->setRenderHint(QPainter::Antialiasing, antialiasButton->isChecked());
+}
+
+void View::print()
+{
+#ifndef QT_NO_PRINTER
+ QPrinter printer;
+ QPrintDialog dialog(&printer, this);
+ if (dialog.exec() == QDialog::Accepted) {
+ QPainter painter(&printer);
+ graphicsView->render(&painter);
+ }
+#endif
+}
+
+void View::zoomIn()
+{
+ zoomSlider->setValue(zoomSlider->value() + 1);
+}
+
+void View::zoomOut()
+{
+ zoomSlider->setValue(zoomSlider->value() - 1);
+}
+
+void View::rotateLeft()
+{
+ rotateSlider->setValue(rotateSlider->value() - 10);
+}
+
+void View::rotateRight()
+{
+ rotateSlider->setValue(rotateSlider->value() + 10);
+}
+
diff --git a/demos/chip/view.h b/demos/chip/view.h
new file mode 100644
index 0000000..4987f60
--- /dev/null
+++ b/demos/chip/view.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VIEW_H
+#define VIEW_H
+
+#include <QFrame>
+
+QT_FORWARD_DECLARE_CLASS(QGraphicsView)
+QT_FORWARD_DECLARE_CLASS(QLabel)
+QT_FORWARD_DECLARE_CLASS(QSlider)
+QT_FORWARD_DECLARE_CLASS(QToolButton)
+
+class View : public QFrame
+{
+ Q_OBJECT
+public:
+ View(const QString &name, QWidget *parent = 0);
+
+ QGraphicsView *view() const;
+
+private slots:
+ void resetView();
+ void setResetButtonEnabled();
+ void setupMatrix();
+ void toggleOpenGL();
+ void toggleAntialiasing();
+ void print();
+
+ void zoomIn();
+ void zoomOut();
+ void rotateLeft();
+ void rotateRight();
+
+private:
+ QGraphicsView *graphicsView;
+ QLabel *label;
+ QToolButton *openGlButton;
+ QToolButton *antialiasButton;
+ QToolButton *printButton;
+ QToolButton *resetButton;
+ QSlider *zoomSlider;
+ QSlider *rotateSlider;
+};
+
+#endif
diff --git a/demos/chip/zoomin.png b/demos/chip/zoomin.png
new file mode 100644
index 0000000..8b0daee
--- /dev/null
+++ b/demos/chip/zoomin.png
Binary files differ
diff --git a/demos/chip/zoomout.png b/demos/chip/zoomout.png
new file mode 100644
index 0000000..1575dd2
--- /dev/null
+++ b/demos/chip/zoomout.png
Binary files differ
diff --git a/demos/composition/composition.cpp b/demos/composition/composition.cpp
new file mode 100644
index 0000000..b43c66b
--- /dev/null
+++ b/demos/composition/composition.cpp
@@ -0,0 +1,511 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "composition.h"
+#include <QBoxLayout>
+#include <QRadioButton>
+#include <QTimer>
+#include <QDateTime>
+#include <QSlider>
+#include <QMouseEvent>
+#include <qmath.h>
+
+CompositionWidget::CompositionWidget(QWidget *parent)
+ : QWidget(parent)
+{
+ CompositionRenderer *view = new CompositionRenderer(this);
+
+ QGroupBox *mainGroup = new QGroupBox(parent);
+ mainGroup->setTitle(tr("Composition Modes"));
+
+ QGroupBox *modesGroup = new QGroupBox(mainGroup);
+ modesGroup->setTitle(tr("Mode"));
+
+ rbClear = new QRadioButton(tr("Clear"), modesGroup);
+ connect(rbClear, SIGNAL(clicked()), view, SLOT(setClearMode()));
+ rbSource = new QRadioButton(tr("Source"), modesGroup);
+ connect(rbSource, SIGNAL(clicked()), view, SLOT(setSourceMode()));
+ rbDest = new QRadioButton(tr("Destination"), modesGroup);
+ connect(rbDest, SIGNAL(clicked()), view, SLOT(setDestMode()));
+ rbSourceOver = new QRadioButton(tr("Source Over"), modesGroup);
+ connect(rbSourceOver, SIGNAL(clicked()), view, SLOT(setSourceOverMode()));
+ rbDestOver = new QRadioButton(tr("Destination Over"), modesGroup);
+ connect(rbDestOver, SIGNAL(clicked()), view, SLOT(setDestOverMode()));
+ rbSourceIn = new QRadioButton(tr("Source In"), modesGroup);
+ connect(rbSourceIn, SIGNAL(clicked()), view, SLOT(setSourceInMode()));
+ rbDestIn = new QRadioButton(tr("Dest In"), modesGroup);
+ connect(rbDestIn, SIGNAL(clicked()), view, SLOT(setDestInMode()));
+ rbSourceOut = new QRadioButton(tr("Source Out"), modesGroup);
+ connect(rbSourceOut, SIGNAL(clicked()), view, SLOT(setSourceOutMode()));
+ rbDestOut = new QRadioButton(tr("Dest Out"), modesGroup);
+ connect(rbDestOut, SIGNAL(clicked()), view, SLOT(setDestOutMode()));
+ rbSourceAtop = new QRadioButton(tr("Source Atop"), modesGroup);
+ connect(rbSourceAtop, SIGNAL(clicked()), view, SLOT(setSourceAtopMode()));
+ rbDestAtop = new QRadioButton(tr("Dest Atop"), modesGroup);
+ connect(rbDestAtop, SIGNAL(clicked()), view, SLOT(setDestAtopMode()));
+ rbXor = new QRadioButton(tr("Xor"), modesGroup);
+ connect(rbXor, SIGNAL(clicked()), view, SLOT(setXorMode()));
+
+ rbPlus = new QRadioButton(tr("Plus"), modesGroup);
+ connect(rbPlus, SIGNAL(clicked()), view, SLOT(setPlusMode()));
+ rbMultiply = new QRadioButton(tr("Multiply"), modesGroup);
+ connect(rbMultiply, SIGNAL(clicked()), view, SLOT(setMultiplyMode()));
+ rbScreen = new QRadioButton(tr("Screen"), modesGroup);
+ connect(rbScreen, SIGNAL(clicked()), view, SLOT(setScreenMode()));
+ rbOverlay = new QRadioButton(tr("Overlay"), modesGroup);
+ connect(rbOverlay, SIGNAL(clicked()), view, SLOT(setOverlayMode()));
+ rbDarken = new QRadioButton(tr("Darken"), modesGroup);
+ connect(rbDarken, SIGNAL(clicked()), view, SLOT(setDarkenMode()));
+ rbLighten = new QRadioButton(tr("Lighten"), modesGroup);
+ connect(rbLighten, SIGNAL(clicked()), view, SLOT(setLightenMode()));
+ rbColorDodge = new QRadioButton(tr("Color Dodge"), modesGroup);
+ connect(rbColorDodge, SIGNAL(clicked()), view, SLOT(setColorDodgeMode()));
+ rbColorBurn = new QRadioButton(tr("Color Burn"), modesGroup);
+ connect(rbColorBurn, SIGNAL(clicked()), view, SLOT(setColorBurnMode()));
+ rbHardLight = new QRadioButton(tr("Hard Light"), modesGroup);
+ connect(rbHardLight, SIGNAL(clicked()), view, SLOT(setHardLightMode()));
+ rbSoftLight = new QRadioButton(tr("Soft Light"), modesGroup);
+ connect(rbSoftLight, SIGNAL(clicked()), view, SLOT(setSoftLightMode()));
+ rbDifference = new QRadioButton(tr("Difference"), modesGroup);
+ connect(rbDifference, SIGNAL(clicked()), view, SLOT(setDifferenceMode()));
+ rbExclusion = new QRadioButton(tr("Exclusion"), modesGroup);
+ connect(rbExclusion, SIGNAL(clicked()), view, SLOT(setExclusionMode()));
+
+ QGroupBox *circleColorGroup = new QGroupBox(mainGroup);
+ circleColorGroup->setTitle(tr("Circle color"));
+ QSlider *circleColorSlider = new QSlider(Qt::Horizontal, circleColorGroup);
+ circleColorSlider->setRange(0, 359);
+ circleColorSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ connect(circleColorSlider, SIGNAL(valueChanged(int)), view, SLOT(setCircleColor(int)));
+
+ QGroupBox *circleAlphaGroup = new QGroupBox(mainGroup);
+ circleAlphaGroup->setTitle(tr("Circle alpha"));
+ QSlider *circleAlphaSlider = new QSlider(Qt::Horizontal, circleAlphaGroup);
+ circleAlphaSlider->setRange(0, 255);
+ circleAlphaSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ connect(circleAlphaSlider, SIGNAL(valueChanged(int)), view, SLOT(setCircleAlpha(int)));
+
+ QPushButton *showSourceButton = new QPushButton(mainGroup);
+ showSourceButton->setText(tr("Show Source"));
+#if defined(QT_OPENGL_SUPPORT) && !defined(QT_OPENGL_ES)
+ QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
+ enableOpenGLButton->setText(tr("Use OpenGL"));
+ enableOpenGLButton->setCheckable(true);
+ enableOpenGLButton->setChecked(view->usesOpenGL());
+
+ if (!QGLFormat::hasOpenGL() || !QGLPixelBuffer::hasOpenGLPbuffers())
+ enableOpenGLButton->hide();
+#endif
+ QPushButton *whatsThisButton = new QPushButton(mainGroup);
+ whatsThisButton->setText(tr("What's This?"));
+ whatsThisButton->setCheckable(true);
+
+ QPushButton *animateButton = new QPushButton(mainGroup);
+ animateButton->setText(tr("Animated"));
+ animateButton->setCheckable(true);
+ animateButton->setChecked(true);
+
+ QHBoxLayout *viewLayout = new QHBoxLayout(this);
+ viewLayout->addWidget(view);
+ viewLayout->addWidget(mainGroup);
+
+ QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
+ mainGroupLayout->addWidget(circleColorGroup);
+ mainGroupLayout->addWidget(circleAlphaGroup);
+ mainGroupLayout->addWidget(modesGroup);
+ mainGroupLayout->addStretch();
+ mainGroupLayout->addWidget(animateButton);
+ mainGroupLayout->addWidget(whatsThisButton);
+ mainGroupLayout->addWidget(showSourceButton);
+#if defined(QT_OPENGL_SUPPORT) && !defined(QT_OPENGL_ES)
+ mainGroupLayout->addWidget(enableOpenGLButton);
+#endif
+
+ QGridLayout *modesLayout = new QGridLayout(modesGroup);
+ modesLayout->addWidget(rbClear, 0, 0);
+ modesLayout->addWidget(rbSource, 1, 0);
+ modesLayout->addWidget(rbDest, 2, 0);
+ modesLayout->addWidget(rbSourceOver, 3, 0);
+ modesLayout->addWidget(rbDestOver, 4, 0);
+ modesLayout->addWidget(rbSourceIn, 5, 0);
+ modesLayout->addWidget(rbDestIn, 6, 0);
+ modesLayout->addWidget(rbSourceOut, 7, 0);
+ modesLayout->addWidget(rbDestOut, 8, 0);
+ modesLayout->addWidget(rbSourceAtop, 9, 0);
+ modesLayout->addWidget(rbDestAtop, 10, 0);
+ modesLayout->addWidget(rbXor, 11, 0);
+
+ modesLayout->addWidget(rbPlus, 0, 1);
+ modesLayout->addWidget(rbMultiply, 1, 1);
+ modesLayout->addWidget(rbScreen, 2, 1);
+ modesLayout->addWidget(rbOverlay, 3, 1);
+ modesLayout->addWidget(rbDarken, 4, 1);
+ modesLayout->addWidget(rbLighten, 5, 1);
+ modesLayout->addWidget(rbColorDodge, 6, 1);
+ modesLayout->addWidget(rbColorBurn, 7, 1);
+ modesLayout->addWidget(rbHardLight, 8, 1);
+ modesLayout->addWidget(rbSoftLight, 9, 1);
+ modesLayout->addWidget(rbDifference, 10, 1);
+ modesLayout->addWidget(rbExclusion, 11, 1);
+
+
+ QVBoxLayout *circleColorLayout = new QVBoxLayout(circleColorGroup);
+ circleColorLayout->addWidget(circleColorSlider);
+
+ QVBoxLayout *circleAlphaLayout = new QVBoxLayout(circleAlphaGroup);
+ circleAlphaLayout->addWidget(circleAlphaSlider);
+
+ view->loadDescription(":res/composition/composition.html");
+ view->loadSourceFile(":res/composition/composition.cpp");
+
+ connect(whatsThisButton, SIGNAL(clicked(bool)), view, SLOT(setDescriptionEnabled(bool)));
+ connect(view, SIGNAL(descriptionEnabledChanged(bool)), whatsThisButton, SLOT(setChecked(bool)));
+ connect(showSourceButton, SIGNAL(clicked()), view, SLOT(showSource()));
+#if defined(QT_OPENGL_SUPPORT) && !defined(QT_OPENGL_ES)
+ connect(enableOpenGLButton, SIGNAL(clicked(bool)), view, SLOT(enableOpenGL(bool)));
+#endif
+ connect(animateButton, SIGNAL(toggled(bool)), view, SLOT(setAnimationEnabled(bool)));
+
+ circleColorSlider->setValue(270);
+ circleAlphaSlider->setValue(200);
+ rbSourceOut->animateClick();
+
+ setWindowTitle(tr("Composition Modes"));
+}
+
+
+void CompositionWidget::nextMode()
+{
+ /*
+ if (!m_animation_enabled)
+ return;
+ if (rbClear->isChecked()) rbSource->animateClick();
+ if (rbSource->isChecked()) rbDest->animateClick();
+ if (rbDest->isChecked()) rbSourceOver->animateClick();
+ if (rbSourceOver->isChecked()) rbDestOver->animateClick();
+ if (rbDestOver->isChecked()) rbSourceIn->animateClick();
+ if (rbSourceIn->isChecked()) rbDestIn->animateClick();
+ if (rbDestIn->isChecked()) rbSourceOut->animateClick();
+ if (rbSourceOut->isChecked()) rbDestOut->animateClick();
+ if (rbDestOut->isChecked()) rbSourceAtop->animateClick();
+ if (rbSourceAtop->isChecked()) rbDestAtop->animateClick();
+ if (rbDestAtop->isChecked()) rbXor->animateClick();
+ if (rbXor->isChecked()) rbClear->animateClick();
+ */
+}
+
+CompositionRenderer::CompositionRenderer(QWidget *parent)
+ : ArthurFrame(parent)
+{
+ m_animation_enabled = true;
+#ifdef Q_WS_QWS
+ m_image = QPixmap(":res/composition/flower.jpg");
+ m_image.setAlphaChannel(QPixmap(":res/composition/flower_alpha.jpg"));
+#else
+ m_image = QImage(":res/composition/flower.jpg");
+ m_image.setAlphaChannel(QImage(":res/composition/flower_alpha.jpg"));
+#endif
+ m_circle_alpha = 127;
+ m_circle_hue = 255;
+ m_current_object = NoObject;
+ m_composition_mode = QPainter::CompositionMode_SourceOut;
+
+ m_circle_pos = QPoint(200, 100);
+
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+#ifdef QT_OPENGL_SUPPORT
+ m_pbuffer = 0;
+ m_pbuffer_size = 1024;
+#endif
+}
+
+QRectF rectangle_around(const QPointF &p, const QSizeF &size = QSize(250, 200))
+{
+ QRectF rect(p, size);
+ rect.translate(-size.width()/2, -size.height()/2);
+ return rect;
+}
+
+void CompositionRenderer::updateCirclePos()
+{
+ if (m_current_object != NoObject)
+ return;
+ QDateTime dt = QDateTime::currentDateTime();
+ qreal t = (dt.toTime_t() * 1000 + dt.time().msec()) / 1000.0;
+
+ qreal x = width() / qreal(2) + (qCos(t*8/11) + qSin(-t)) * width() / qreal(4);
+ qreal y = height() / qreal(2) + (qSin(t*6/7) + qCos(t * qreal(1.5))) * height() / qreal(4);
+
+ setCirclePos(QLineF(m_circle_pos, QPointF(x, y)).pointAt(0.02));
+}
+
+void CompositionRenderer::drawBase(QPainter &p)
+{
+ p.setPen(Qt::NoPen);
+
+ QLinearGradient rect_gradient(0, 0, 0, height());
+ rect_gradient.setColorAt(0, Qt::red);
+ rect_gradient.setColorAt(.17, Qt::yellow);
+ rect_gradient.setColorAt(.33, Qt::green);
+ rect_gradient.setColorAt(.50, Qt::cyan);
+ rect_gradient.setColorAt(.66, Qt::blue);
+ rect_gradient.setColorAt(.81, Qt::magenta);
+ rect_gradient.setColorAt(1, Qt::red);
+ p.setBrush(rect_gradient);
+ p.drawRect(width() / 2, 0, width() / 2, height());
+
+ QLinearGradient alpha_gradient(0, 0, width(), 0);
+ alpha_gradient.setColorAt(0, Qt::white);
+ alpha_gradient.setColorAt(0.2, Qt::white);
+ alpha_gradient.setColorAt(0.5, Qt::transparent);
+ alpha_gradient.setColorAt(0.8, Qt::white);
+ alpha_gradient.setColorAt(1, Qt::white);
+
+ p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+ p.setBrush(alpha_gradient);
+ p.drawRect(0, 0, width(), height());
+
+ p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
+
+ p.setPen(Qt::NoPen);
+ p.setRenderHint(QPainter::SmoothPixmapTransform);
+#ifdef Q_WS_QWS
+ p.drawPixmap(rect(), m_image);
+#else
+ p.drawImage(rect(), m_image);
+#endif
+}
+
+void CompositionRenderer::drawSource(QPainter &p)
+{
+ p.setPen(Qt::NoPen);
+ p.setRenderHint(QPainter::Antialiasing);
+ p.setCompositionMode(m_composition_mode);
+
+ QRectF circle_rect = rectangle_around(m_circle_pos);
+ QColor color = QColor::fromHsvF(m_circle_hue / 360.0, 1, 1, m_circle_alpha / 255.0);
+ QLinearGradient circle_gradient(circle_rect.topLeft(), circle_rect.bottomRight());
+ circle_gradient.setColorAt(0, color.light());
+ circle_gradient.setColorAt(0.5, color);
+ circle_gradient.setColorAt(1, color.dark());
+ p.setBrush(circle_gradient);
+
+ p.drawEllipse(circle_rect);
+}
+
+void CompositionRenderer::paint(QPainter *painter)
+{
+#if defined(QT_OPENGL_SUPPORT) && !defined(QT_OPENGL_ES)
+ if (usesOpenGL()) {
+
+ int new_pbuf_size = m_pbuffer_size;
+ if (size().width() > m_pbuffer_size ||
+ size().height() > m_pbuffer_size)
+ new_pbuf_size *= 2;
+
+ if (size().width() < m_pbuffer_size/2 &&
+ size().height() < m_pbuffer_size/2)
+ new_pbuf_size /= 2;
+
+ if (!m_pbuffer || new_pbuf_size != m_pbuffer_size) {
+ if (m_pbuffer) {
+ m_pbuffer->deleteTexture(m_base_tex);
+ m_pbuffer->deleteTexture(m_compositing_tex);
+ delete m_pbuffer;
+ }
+
+ m_pbuffer = new QGLPixelBuffer(QSize(new_pbuf_size, new_pbuf_size), QGLFormat::defaultFormat(), glWidget());
+ m_pbuffer->makeCurrent();
+ m_base_tex = m_pbuffer->generateDynamicTexture();
+ m_compositing_tex = m_pbuffer->generateDynamicTexture();
+ m_pbuffer_size = new_pbuf_size;
+ }
+
+ if (size() != m_previous_size) {
+ m_previous_size = size();
+ QPainter p(m_pbuffer);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.fillRect(QRect(0, 0, m_pbuffer->width(), m_pbuffer->height()), Qt::transparent);
+ drawBase(p);
+ p.end();
+ m_pbuffer->updateDynamicTexture(m_base_tex);
+ }
+
+ qreal x_fraction = width()/float(m_pbuffer->width());
+ qreal y_fraction = height()/float(m_pbuffer->height());
+
+ {
+ QPainter p(m_pbuffer);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.fillRect(QRect(0, 0, m_pbuffer->width(), m_pbuffer->height()), Qt::transparent);
+
+ p.save();
+ glBindTexture(GL_TEXTURE_2D, m_base_tex);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1.,1.,1.,1.);
+
+ glBegin(GL_QUADS);
+ {
+ glTexCoord2f(0, 1.0);
+ glVertex2f(0, 0);
+
+ glTexCoord2f(x_fraction, 1.0);
+ glVertex2f(width(), 0);
+
+ glTexCoord2f(x_fraction, 1.0-y_fraction);
+ glVertex2f(width(), height());
+
+ glTexCoord2f(0, 1.0-y_fraction);
+ glVertex2f(0, height());
+ }
+ glEnd();
+
+ glDisable(GL_TEXTURE_2D);
+ p.restore();
+
+ drawSource(p);
+ p.end();
+ m_pbuffer->updateDynamicTexture(m_compositing_tex);
+ }
+
+ glWidget()->makeCurrent();
+ glBindTexture(GL_TEXTURE_2D, m_compositing_tex);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1.,1.,1.,1.);
+ glBegin(GL_QUADS);
+ {
+ glTexCoord2f(0, 1.0);
+ glVertex2f(0, 0);
+
+ glTexCoord2f(x_fraction, 1.0);
+ glVertex2f(width(), 0);
+
+ glTexCoord2f(x_fraction, 1.0-y_fraction);
+ glVertex2f(width(), height());
+
+ glTexCoord2f(0, 1.0-y_fraction);
+ glVertex2f(0, height());
+ }
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+ } else
+#endif
+ {
+ // using a QImage
+ if (m_buffer.size() != size()) {
+#ifdef Q_WS_QWS
+ m_base_buffer = QPixmap(size());
+ m_base_buffer.fill(Qt::transparent);
+#else
+ m_buffer = QImage(size(), QImage::Format_ARGB32_Premultiplied);
+ m_base_buffer = QImage(size(), QImage::Format_ARGB32_Premultiplied);
+
+ m_base_buffer.fill(0);
+#endif
+
+ QPainter p(&m_base_buffer);
+
+ drawBase(p);
+ }
+
+#ifdef Q_WS_QWS
+ m_buffer = m_base_buffer;
+#else
+ memcpy(m_buffer.bits(), m_base_buffer.bits(), m_buffer.numBytes());
+#endif
+
+ {
+ QPainter p(&m_buffer);
+ drawSource(p);
+ }
+
+#ifdef Q_WS_QWS
+ painter->drawPixmap(0, 0, m_buffer);
+#else
+ painter->drawImage(0, 0, m_buffer);
+#endif
+ }
+
+ if (m_animation_enabled && m_current_object == NoObject) {
+ updateCirclePos();
+ }
+}
+
+void CompositionRenderer::mousePressEvent(QMouseEvent *e)
+{
+ setDescriptionEnabled(false);
+
+ QRectF circle = rectangle_around(m_circle_pos);
+
+ if (circle.contains(e->pos())) {
+ m_current_object = Circle;
+ m_offset = circle.center() - e->pos();
+ } else {
+ m_current_object = NoObject;
+ }
+}
+
+void CompositionRenderer::mouseMoveEvent(QMouseEvent *e)
+{
+ if (m_current_object == Circle) setCirclePos(e->pos() + m_offset);
+}
+
+void CompositionRenderer::mouseReleaseEvent(QMouseEvent *)
+{
+ m_current_object = NoObject;
+
+ if (m_animation_enabled)
+ updateCirclePos();
+}
+
+void CompositionRenderer::setCirclePos(const QPointF &pos)
+{
+ const QRect oldRect = rectangle_around(m_circle_pos).toAlignedRect();
+ m_circle_pos = pos;
+ const QRect newRect = rectangle_around(m_circle_pos).toAlignedRect();
+#if defined(QT_OPENGL_SUPPORT) && !defined(QT_OPENGL_ES)
+ if (usesOpenGL())
+ update();
+ else
+#endif
+ update(oldRect | newRect);
+}
+
diff --git a/demos/composition/composition.h b/demos/composition/composition.h
new file mode 100644
index 0000000..1d504d0
--- /dev/null
+++ b/demos/composition/composition.h
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef COMPOSITION_H
+#define COMPOSITION_H
+
+#include "arthurwidgets.h"
+
+#include <QPainter>
+#include <QEvent>
+
+QT_FORWARD_DECLARE_CLASS(QPushButton)
+QT_FORWARD_DECLARE_CLASS(QRadioButton)
+
+#ifdef QT_OPENGL_SUPPORT
+#include <QtOpenGL>
+#endif
+
+class CompositionWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ CompositionWidget(QWidget *parent);
+
+public slots:
+void nextMode();
+
+private:
+ bool m_cycle_enabled;
+
+ QRadioButton *rbClear;
+ QRadioButton *rbSource;
+ QRadioButton *rbDest;
+ QRadioButton *rbSourceOver;
+ QRadioButton *rbDestOver;
+ QRadioButton *rbSourceIn;
+ QRadioButton *rbDestIn;
+ QRadioButton *rbSourceOut;
+ QRadioButton *rbDestOut;
+ QRadioButton *rbSourceAtop;
+ QRadioButton *rbDestAtop;
+ QRadioButton *rbXor;
+
+ QRadioButton *rbPlus;
+ QRadioButton *rbMultiply;
+ QRadioButton *rbScreen;
+ QRadioButton *rbOverlay;
+ QRadioButton *rbDarken;
+ QRadioButton *rbLighten;
+ QRadioButton *rbColorDodge;
+ QRadioButton *rbColorBurn;
+ QRadioButton *rbHardLight;
+ QRadioButton *rbSoftLight;
+ QRadioButton *rbDifference;
+ QRadioButton *rbExclusion;
+};
+
+class CompositionRenderer : public ArthurFrame
+{
+ Q_OBJECT
+
+ enum ObjectType { NoObject, Circle, Rectangle, Image };
+
+ Q_PROPERTY(int circleColor READ circleColor WRITE setCircleColor)
+ Q_PROPERTY(int circleAlpha READ circleAlpha WRITE setCircleAlpha)
+ Q_PROPERTY(bool animation READ animationEnabled WRITE setAnimationEnabled)
+
+public:
+ CompositionRenderer(QWidget *parent);
+
+ void paint(QPainter *);
+
+ void mousePressEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+
+ void setCirclePos(const QPointF &pos);
+
+ QSize sizeHint() const { return QSize(500, 400); }
+
+ bool animationEnabled() const { return m_animation_enabled; }
+ int circleColor() const { return m_circle_hue; }
+ int circleAlpha() const { return m_circle_alpha; }
+
+public slots:
+ void setClearMode() { m_composition_mode = QPainter::CompositionMode_Clear; update(); }
+ void setSourceMode() { m_composition_mode = QPainter::CompositionMode_Source; update(); }
+ void setDestMode() { m_composition_mode = QPainter::CompositionMode_Destination; update(); }
+ void setSourceOverMode() { m_composition_mode = QPainter::CompositionMode_SourceOver; update(); }
+ void setDestOverMode() { m_composition_mode = QPainter::CompositionMode_DestinationOver; update(); }
+ void setSourceInMode() { m_composition_mode = QPainter::CompositionMode_SourceIn; update(); }
+ void setDestInMode() { m_composition_mode = QPainter::CompositionMode_DestinationIn; update(); }
+ void setSourceOutMode() { m_composition_mode = QPainter::CompositionMode_SourceOut; update(); }
+ void setDestOutMode() { m_composition_mode = QPainter::CompositionMode_DestinationOut; update(); }
+ void setSourceAtopMode() { m_composition_mode = QPainter::CompositionMode_SourceAtop; update(); }
+ void setDestAtopMode() { m_composition_mode = QPainter::CompositionMode_DestinationAtop; update(); }
+ void setXorMode() { m_composition_mode = QPainter::CompositionMode_Xor; update(); }
+
+ void setPlusMode() { m_composition_mode = QPainter::CompositionMode_Plus; update(); }
+ void setMultiplyMode() { m_composition_mode = QPainter::CompositionMode_Multiply; update(); }
+ void setScreenMode() { m_composition_mode = QPainter::CompositionMode_Screen; update(); }
+ void setOverlayMode() { m_composition_mode = QPainter::CompositionMode_Overlay; update(); }
+ void setDarkenMode() { m_composition_mode = QPainter::CompositionMode_Darken; update(); }
+ void setLightenMode() { m_composition_mode = QPainter::CompositionMode_Lighten; update(); }
+ void setColorDodgeMode() { m_composition_mode = QPainter::CompositionMode_ColorDodge; update(); }
+ void setColorBurnMode() { m_composition_mode = QPainter::CompositionMode_ColorBurn; update(); }
+ void setHardLightMode() { m_composition_mode = QPainter::CompositionMode_HardLight; update(); }
+ void setSoftLightMode() { m_composition_mode = QPainter::CompositionMode_SoftLight; update(); }
+ void setDifferenceMode() { m_composition_mode = QPainter::CompositionMode_Difference; update(); }
+ void setExclusionMode() { m_composition_mode = QPainter::CompositionMode_Exclusion; update(); }
+
+ void setCircleAlpha(int alpha) { m_circle_alpha = alpha; update(); }
+ void setCircleColor(int hue) { m_circle_hue = hue; update(); }
+ void setAnimationEnabled(bool enabled) { m_animation_enabled = enabled; update(); }
+
+private:
+ void updateCirclePos();
+ void drawBase(QPainter &p);
+ void drawSource(QPainter &p);
+
+ QPainter::CompositionMode m_composition_mode;
+
+#ifdef Q_WS_QWS
+ QPixmap m_image;
+ QPixmap m_buffer;
+ QPixmap m_base_buffer;
+#else
+ QImage m_image;
+ QImage m_buffer;
+ QImage m_base_buffer;
+#endif
+
+ int m_circle_alpha;
+ int m_circle_hue;
+
+ QPointF m_circle_pos;
+ QPointF m_offset;
+
+ ObjectType m_current_object;
+ bool m_animation_enabled;
+
+#ifdef QT_OPENGL_SUPPORT
+ QGLPixelBuffer *m_pbuffer;
+ GLuint m_base_tex;
+ GLuint m_compositing_tex;
+ int m_pbuffer_size; // width==height==size of pbuffer
+ QSize m_previous_size;
+#endif
+};
+
+#endif // COMPOSITION_H
diff --git a/demos/composition/composition.html b/demos/composition/composition.html
new file mode 100644
index 0000000..1848ad8
--- /dev/null
+++ b/demos/composition/composition.html
@@ -0,0 +1,23 @@
+<html>
+
+<h1>Demo for composition modes</h1>
+
+<p>
+ This demo shows some of the more advanced composition modes supported by Qt.
+</p>
+
+<p>
+ The two most common forms of composition are <b>Source</b> and <b>SourceOver</b>.
+ <b>Source</b> is used to draw opaque objects onto a paint device. In this mode,
+ each pixel in the source replaces the corresponding pixel in the destination.
+ In <b>SourceOver</b> composition mode, the source object is transparent and is
+ drawn on top of the destination.
+</p>
+
+<p>
+ In addition to these standard modes, Qt defines the complete set of composition
+ modes as defined by Thomas Porter and Tom Duff. See the <tt>QPainter</tt> documentation
+ for details.
+</p>
+
+</html>
diff --git a/demos/composition/composition.pro b/demos/composition/composition.pro
new file mode 100644
index 0000000..90562eb
--- /dev/null
+++ b/demos/composition/composition.pro
@@ -0,0 +1,29 @@
+SOURCES += main.cpp composition.cpp
+HEADERS += composition.h
+
+SHARED_FOLDER = ../shared
+
+include($$SHARED_FOLDER/shared.pri)
+
+RESOURCES += composition.qrc
+contains(QT_CONFIG, opengl) {
+ DEFINES += QT_OPENGL_SUPPORT
+ QT += opengl
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/composition
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.png *.jpg *.pro *.html
+sources.path = $$[QT_INSTALL_DEMOS]/composition
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
+win32-msvc* {
+ QMAKE_CXXFLAGS += /Zm500
+ QMAKE_CFLAGS += /Zm500
+}
+
+wince* {
+ DEPLOYMENT_PLUGIN += qjpeg
+}
diff --git a/demos/composition/composition.qrc b/demos/composition/composition.qrc
new file mode 100644
index 0000000..d02c397
--- /dev/null
+++ b/demos/composition/composition.qrc
@@ -0,0 +1,8 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/res/composition">
+ <file>composition.cpp</file>
+ <file>composition.html</file>
+ <file>flower.jpg</file>
+ <file>flower_alpha.jpg</file>
+</qresource>
+</RCC>
diff --git a/demos/composition/flower.jpg b/demos/composition/flower.jpg
new file mode 100644
index 0000000..f8e022c
--- /dev/null
+++ b/demos/composition/flower.jpg
Binary files differ
diff --git a/demos/composition/flower_alpha.jpg b/demos/composition/flower_alpha.jpg
new file mode 100644
index 0000000..6a3c2a0
--- /dev/null
+++ b/demos/composition/flower_alpha.jpg
Binary files differ
diff --git a/demos/composition/main.cpp b/demos/composition/main.cpp
new file mode 100644
index 0000000..74055b2
--- /dev/null
+++ b/demos/composition/main.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "composition.h"
+
+#include <QApplication>
+
+int main(int argc, char **argv)
+{
+ // Q_INIT_RESOURCE(deform);
+
+ QApplication app(argc, argv);
+
+ CompositionWidget compWidget(0);
+ QStyle *arthurStyle = new ArthurStyle();
+ compWidget.setStyle(arthurStyle);
+
+ QList<QWidget *> widgets = qFindChildren<QWidget *>(&compWidget);
+ foreach (QWidget *w, widgets)
+ w->setStyle(arthurStyle);
+ compWidget.show();
+
+ return app.exec();
+}
diff --git a/demos/deform/deform.pro b/demos/deform/deform.pro
new file mode 100644
index 0000000..31ba2e9
--- /dev/null
+++ b/demos/deform/deform.pro
@@ -0,0 +1,23 @@
+SOURCES += main.cpp pathdeform.cpp
+HEADERS += pathdeform.h
+
+SHARED_FOLDER = ../shared
+
+include($$SHARED_FOLDER/shared.pri)
+
+RESOURCES += deform.qrc
+
+contains(QT_CONFIG, opengl) {
+ DEFINES += QT_OPENGL_SUPPORT
+ QT += opengl
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/deform
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.html
+sources.path = $$[QT_INSTALL_DEMOS]/deform
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
+symbian:TARGET.UID3 = 0xA000A63D
diff --git a/demos/deform/deform.qrc b/demos/deform/deform.qrc
new file mode 100644
index 0000000..2e59ebc
--- /dev/null
+++ b/demos/deform/deform.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/res/deform">
+ <file>pathdeform.cpp</file>
+ <file>pathdeform.html</file>
+</qresource>
+</RCC>
diff --git a/demos/deform/main.cpp b/demos/deform/main.cpp
new file mode 100644
index 0000000..e32fa12
--- /dev/null
+++ b/demos/deform/main.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pathdeform.h"
+
+#include <QApplication>
+#include <QDebug>
+
+int main(int argc, char **argv)
+{
+ Q_INIT_RESOURCE(deform);
+
+ QApplication app(argc, argv);
+
+ bool smallScreen = false;
+ for (int i=0; i<argc; i++)
+ if (QString(argv[i]) == "-small-screen")
+ smallScreen = true;
+
+ PathDeformWidget deformWidget(0, smallScreen);
+
+ QStyle *arthurStyle = new ArthurStyle();
+ deformWidget.setStyle(arthurStyle);
+ QList<QWidget *> widgets = qFindChildren<QWidget *>(&deformWidget);
+ foreach (QWidget *w, widgets)
+ w->setStyle(arthurStyle);
+
+ if (smallScreen)
+ deformWidget.showFullScreen();
+ else
+ deformWidget.show();
+
+ return app.exec();
+}
diff --git a/demos/deform/pathdeform.cpp b/demos/deform/pathdeform.cpp
new file mode 100644
index 0000000..4026241
--- /dev/null
+++ b/demos/deform/pathdeform.cpp
@@ -0,0 +1,659 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pathdeform.h"
+
+#include <QApplication>
+#include <QtDebug>
+#include <QMouseEvent>
+#include <QTimerEvent>
+#include <QLayout>
+#include <QLineEdit>
+#include <QPainter>
+#include <QSlider>
+#include <QLabel>
+#include <QDesktopWidget>
+#include <qmath.h>
+
+#if defined(Q_OS_SYMBIAN)
+// TODO: Remove all FONT_OUTLINE_TWEAK related code as soon as the S60FontEngine can deliver outlines
+#define FONT_OUTLINE_TWEAK
+#endif
+
+PathDeformControls::PathDeformControls(QWidget *parent, PathDeformRenderer* renderer, bool smallScreen)
+ : QWidget(parent)
+{
+ m_renderer = renderer;
+
+ if (smallScreen)
+ layoutForSmallScreen();
+ else
+ layoutForDesktop();
+}
+
+
+void PathDeformControls::layoutForDesktop()
+{
+ QGroupBox* mainGroup = new QGroupBox(this);
+ mainGroup->setTitle(tr("Controls"));
+
+ QGroupBox *radiusGroup = new QGroupBox(mainGroup);
+ radiusGroup->setTitle(tr("Lens Radius"));
+ QSlider *radiusSlider = new QSlider(Qt::Horizontal, radiusGroup);
+ radiusSlider->setRange(15, 150);
+ radiusSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ QGroupBox *deformGroup = new QGroupBox(mainGroup);
+ deformGroup->setTitle(tr("Deformation"));
+ QSlider *deformSlider = new QSlider(Qt::Horizontal, deformGroup);
+ deformSlider->setRange(-100, 100);
+ deformSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ QGroupBox *fontSizeGroup = new QGroupBox(mainGroup);
+ fontSizeGroup->setTitle(tr("Font Size"));
+ QSlider *fontSizeSlider = new QSlider(Qt::Horizontal, fontSizeGroup);
+ fontSizeSlider->setRange(16, 200);
+ fontSizeSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ QGroupBox *textGroup = new QGroupBox(mainGroup);
+ textGroup->setTitle(tr("Text"));
+ QLineEdit *textInput = new QLineEdit(textGroup);
+
+ QPushButton *animateButton = new QPushButton(mainGroup);
+ animateButton->setText(tr("Animated"));
+ animateButton->setCheckable(true);
+
+ QPushButton *showSourceButton = new QPushButton(mainGroup);
+ showSourceButton->setText(tr("Show Source"));
+
+#ifdef QT_OPENGL_SUPPORT
+ QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
+ enableOpenGLButton->setText(tr("Use OpenGL"));
+ enableOpenGLButton->setCheckable(true);
+ enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
+ if (!QGLFormat::hasOpenGL())
+ enableOpenGLButton->hide();
+#endif
+
+ QPushButton *whatsThisButton = new QPushButton(mainGroup);
+ whatsThisButton->setText(tr("What's This?"));
+ whatsThisButton->setCheckable(true);
+
+
+ mainGroup->setFixedWidth(180);
+
+ QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
+ mainGroupLayout->addWidget(radiusGroup);
+ mainGroupLayout->addWidget(deformGroup);
+ mainGroupLayout->addWidget(fontSizeGroup);
+ mainGroupLayout->addWidget(textGroup);
+ mainGroupLayout->addWidget(animateButton);
+ mainGroupLayout->addStretch(1);
+#ifdef QT_OPENGL_SUPPORT
+ mainGroupLayout->addWidget(enableOpenGLButton);
+#endif
+ mainGroupLayout->addWidget(showSourceButton);
+ mainGroupLayout->addWidget(whatsThisButton);
+
+ QVBoxLayout *radiusGroupLayout = new QVBoxLayout(radiusGroup);
+ radiusGroupLayout->addWidget(radiusSlider);
+
+ QVBoxLayout *deformGroupLayout = new QVBoxLayout(deformGroup);
+ deformGroupLayout->addWidget(deformSlider);
+
+ QVBoxLayout *fontSizeGroupLayout = new QVBoxLayout(fontSizeGroup);
+ fontSizeGroupLayout->addWidget(fontSizeSlider);
+
+ QVBoxLayout *textGroupLayout = new QVBoxLayout(textGroup);
+ textGroupLayout->addWidget(textInput);
+
+ QVBoxLayout * mainLayout = new QVBoxLayout(this);
+ mainLayout->addWidget(mainGroup);
+ mainLayout->setMargin(0);
+
+ connect(radiusSlider, SIGNAL(valueChanged(int)), m_renderer, SLOT(setRadius(int)));
+ connect(deformSlider, SIGNAL(valueChanged(int)), m_renderer, SLOT(setIntensity(int)));
+ connect(fontSizeSlider, SIGNAL(valueChanged(int)), m_renderer, SLOT(setFontSize(int)));
+ connect(animateButton, SIGNAL(clicked(bool)), m_renderer, SLOT(setAnimated(bool)));
+#ifdef QT_OPENGL_SUPPORT
+ connect(enableOpenGLButton, SIGNAL(clicked(bool)), m_renderer, SLOT(enableOpenGL(bool)));
+#endif
+
+ connect(textInput, SIGNAL(textChanged(QString)), m_renderer, SLOT(setText(QString)));
+ connect(m_renderer, SIGNAL(descriptionEnabledChanged(bool)),
+ whatsThisButton, SLOT(setChecked(bool)));
+ connect(whatsThisButton, SIGNAL(clicked(bool)), m_renderer, SLOT(setDescriptionEnabled(bool)));
+ connect(showSourceButton, SIGNAL(clicked()), m_renderer, SLOT(showSource()));
+
+ animateButton->animateClick();
+ deformSlider->setValue(80);
+ fontSizeSlider->setValue(120);
+ radiusSlider->setValue(100);
+ textInput->setText(tr("Qt"));
+}
+
+void PathDeformControls::layoutForSmallScreen()
+{
+ QGroupBox* mainGroup = new QGroupBox(this);
+ mainGroup->setTitle(tr("Controls"));
+
+ QLabel *radiusLabel = new QLabel(mainGroup);
+ radiusLabel->setText(tr("Lens Radius:"));
+ QSlider *radiusSlider = new QSlider(Qt::Horizontal, mainGroup);
+ radiusSlider->setRange(15, 150);
+ radiusSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+
+ QLabel *deformLabel = new QLabel(mainGroup);
+ deformLabel->setText(tr("Deformation:"));
+ QSlider *deformSlider = new QSlider(Qt::Horizontal, mainGroup);
+ deformSlider->setRange(-100, 100);
+ deformSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+
+ QLabel *fontSizeLabel = new QLabel(mainGroup);
+ fontSizeLabel->setText(tr("Font Size:"));
+ QSlider *fontSizeSlider = new QSlider(Qt::Horizontal, mainGroup);
+ fontSizeSlider->setRange(16, 200);
+ fontSizeSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+
+ QPushButton *animateButton = new QPushButton(tr("Animated"), mainGroup);
+ animateButton->setCheckable(true);
+
+#ifdef QT_OPENGL_SUPPORT
+ QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
+ enableOpenGLButton->setText(tr("Use OpenGL"));
+ enableOpenGLButton->setCheckable(mainGroup);
+ enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
+ if (!QGLFormat::hasOpenGL())
+ enableOpenGLButton->hide();
+#endif
+
+ QPushButton *quitButton = new QPushButton(tr("Quit"), mainGroup);
+ QPushButton *okButton = new QPushButton(tr("OK"), mainGroup);
+
+
+ QGridLayout *mainGroupLayout = new QGridLayout(mainGroup);
+ mainGroupLayout->setMargin(0);
+ mainGroupLayout->addWidget(radiusLabel, 0, 0, Qt::AlignRight);
+ mainGroupLayout->addWidget(radiusSlider, 0, 1);
+ mainGroupLayout->addWidget(deformLabel, 1, 0, Qt::AlignRight);
+ mainGroupLayout->addWidget(deformSlider, 1, 1);
+ mainGroupLayout->addWidget(fontSizeLabel, 2, 0, Qt::AlignRight);
+ mainGroupLayout->addWidget(fontSizeSlider, 2, 1);
+ mainGroupLayout->addWidget(animateButton, 3,0, 1,2);
+#ifdef QT_OPENGL_SUPPORT
+ mainGroupLayout->addWidget(enableOpenGLButton, 4,0, 1,2);
+#endif
+
+ QVBoxLayout *mainLayout = new QVBoxLayout(this);
+ mainLayout->addWidget(mainGroup);
+ mainLayout->addStretch(1);
+ mainLayout->addWidget(okButton);
+ mainLayout->addWidget(quitButton);
+
+ connect(quitButton, SIGNAL(clicked()), this, SLOT(emitQuitSignal()));
+ connect(okButton, SIGNAL(clicked()), this, SLOT(emitOkSignal()));
+ connect(radiusSlider, SIGNAL(valueChanged(int)), m_renderer, SLOT(setRadius(int)));
+ connect(deformSlider, SIGNAL(valueChanged(int)), m_renderer, SLOT(setIntensity(int)));
+ connect(fontSizeSlider, SIGNAL(valueChanged(int)), m_renderer, SLOT(setFontSize(int)));
+ connect(animateButton, SIGNAL(clicked(bool)), m_renderer, SLOT(setAnimated(bool)));
+#ifdef QT_OPENGL_SUPPORT
+ connect(enableOpenGLButton, SIGNAL(clicked(bool)), m_renderer, SLOT(enableOpenGL(bool)));
+#endif
+
+
+ animateButton->animateClick();
+ deformSlider->setValue(80);
+ fontSizeSlider->setValue(120);
+
+ QRect screen_size = QApplication::desktop()->screenGeometry();
+ radiusSlider->setValue(qMin(screen_size.width(), screen_size.height())/5);
+
+#ifdef FONT_OUTLINE_TWEAK
+ radiusSlider->setValue(qMin(screen_size.width(), screen_size.height())/7);
+ fontSizeLabel->setText("Qt Logo Size:");
+ m_renderer->setText("A"); // Any Letter would be fine
+ fontSizeSlider->setValue(100);
+#endif
+
+ m_renderer->setText(tr("Qt"));
+}
+
+
+void PathDeformControls::emitQuitSignal()
+{ emit quitPressed(); }
+
+void PathDeformControls::emitOkSignal()
+{ emit okPressed(); }
+
+
+PathDeformWidget::PathDeformWidget(QWidget *parent, bool smallScreen)
+ : QWidget(parent)
+{
+ setWindowTitle(tr("Vector Deformation"));
+
+ m_renderer = new PathDeformRenderer(this, smallScreen);
+ m_renderer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+ // Layouts
+ QHBoxLayout *mainLayout = new QHBoxLayout(this);
+ mainLayout->addWidget(m_renderer);
+
+ m_controls = new PathDeformControls(0, m_renderer, smallScreen);
+ m_controls->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
+
+ if (!smallScreen)
+ mainLayout->addWidget(m_controls);
+
+ m_renderer->loadSourceFile(":res/deform/pathdeform.cpp");
+ m_renderer->loadDescription(":res/deform/pathdeform.html");
+ m_renderer->setDescriptionEnabled(false);
+
+ connect(m_renderer, SIGNAL(clicked()), this, SLOT(showControls()));
+ connect(m_controls, SIGNAL(okPressed()), this, SLOT(hideControls()));
+ connect(m_controls, SIGNAL(quitPressed()), QApplication::instance(), SLOT(quit()));
+}
+
+
+void PathDeformWidget::showControls()
+{
+ m_controls->showFullScreen();
+}
+
+void PathDeformWidget::hideControls()
+{
+ m_controls->hide();
+}
+
+void PathDeformWidget::setStyle( QStyle * style )
+{
+ QWidget::setStyle(style);
+ if (m_controls != 0)
+ {
+ m_controls->setStyle(style);
+
+ QList<QWidget *> widgets = qFindChildren<QWidget *>(m_controls);
+ foreach (QWidget *w, widgets)
+ w->setStyle(style);
+ }
+}
+
+static inline QRect circle_bounds(const QPointF &center, qreal radius, qreal compensation)
+{
+ return QRect(qRound(center.x() - radius - compensation),
+ qRound(center.y() - radius - compensation),
+ qRound((radius + compensation) * 2),
+ qRound((radius + compensation) * 2));
+
+}
+
+const int LENS_EXTENT = 10;
+
+PathDeformRenderer::PathDeformRenderer(QWidget *widget, bool smallScreen)
+ : ArthurFrame(widget)
+{
+ m_radius = 100;
+ m_pos = QPointF(m_radius, m_radius);
+ m_direction = QPointF(1, 1);
+ m_fontSize = 24;
+ m_animated = true;
+ m_repaintTimer.start(25, this);
+ m_repaintTracker.start();
+ m_intensity = 100;
+ m_smallScreen = smallScreen;
+
+// m_fpsTimer.start(1000, this);
+// m_fpsCounter = 0;
+
+ generateLensPixmap();
+}
+
+void PathDeformRenderer::setText(const QString &text)
+{
+ m_text = text;
+
+ QFont f("times new roman,utopia");
+ f.setStyleStrategy(QFont::ForceOutline);
+ f.setPointSize(m_fontSize);
+ f.setStyleHint(QFont::Times);
+
+ QFontMetrics fm(f);
+
+ m_paths.clear();
+ m_pathBounds = QRect();
+
+ QPointF advance(0, 0);
+
+ bool do_quick = true;
+ for (int i=0; i<text.size(); ++i) {
+ if (text.at(i).unicode() >= 0x4ff && text.at(i).unicode() <= 0x1e00) {
+ do_quick = false;
+ break;
+ }
+ }
+
+ if (do_quick) {
+ for (int i=0; i<text.size(); ++i) {
+ QPainterPath path;
+ path.addText(advance, f, text.mid(i, 1));
+ m_pathBounds |= path.boundingRect();
+ m_paths << path;
+ advance += QPointF(fm.width(text.mid(i, 1)), 0);
+ }
+ } else {
+ QPainterPath path;
+ path.addText(advance, f, text);
+ m_pathBounds |= path.boundingRect();
+ m_paths << path;
+ }
+
+ for (int i=0; i<m_paths.size(); ++i)
+ m_paths[i] = m_paths[i] * QMatrix(1, 0, 0, 1, -m_pathBounds.x(), -m_pathBounds.y());
+
+ update();
+}
+
+
+void PathDeformRenderer::generateLensPixmap()
+{
+ qreal rad = m_radius + LENS_EXTENT;
+
+ QRect bounds = circle_bounds(QPointF(), rad, 0);
+
+ QPainter painter;
+
+ if (preferImage()) {
+ m_lens_image = QImage(bounds.size(), QImage::Format_ARGB32_Premultiplied);
+ m_lens_image.fill(0);
+ painter.begin(&m_lens_image);
+ } else {
+ m_lens_pixmap = QPixmap(bounds.size());
+ m_lens_pixmap.fill(Qt::transparent);
+ painter.begin(&m_lens_pixmap);
+ }
+
+ QRadialGradient gr(rad, rad, rad, 3 * rad / 5, 3 * rad / 5);
+ gr.setColorAt(0.0, QColor(255, 255, 255, 191));
+ gr.setColorAt(0.2, QColor(255, 255, 127, 191));
+ gr.setColorAt(0.9, QColor(150, 150, 200, 63));
+ gr.setColorAt(0.95, QColor(0, 0, 0, 127));
+ gr.setColorAt(1, QColor(0, 0, 0, 0));
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.setBrush(gr);
+ painter.setPen(Qt::NoPen);
+ painter.drawEllipse(0, 0, bounds.width(), bounds.height());
+}
+
+
+void PathDeformRenderer::setAnimated(bool animated)
+{
+ m_animated = animated;
+
+ if (m_animated) {
+// m_fpsTimer.start(1000, this);
+// m_fpsCounter = 0;
+ m_repaintTimer.start(25, this);
+ m_repaintTracker.start();
+ } else {
+// m_fpsTimer.stop();
+ m_repaintTimer.stop();
+ }
+}
+
+void PathDeformRenderer::timerEvent(QTimerEvent *e)
+{
+
+ if (e->timerId() == m_repaintTimer.timerId()) {
+
+ if (QLineF(QPointF(0,0), m_direction).length() > 1)
+ m_direction *= 0.995;
+ qreal time = m_repaintTracker.restart();
+
+ QRect rectBefore = circle_bounds(m_pos, m_radius, m_fontSize);
+
+ qreal dx = m_direction.x();
+ qreal dy = m_direction.y();
+ if (time > 0) {
+ dx = dx * time * .1;
+ dy = dy * time * .1;
+ }
+
+ m_pos += QPointF(dx, dy);
+
+
+
+ if (m_pos.x() - m_radius < 0) {
+ m_direction.setX(-m_direction.x());
+ m_pos.setX(m_radius);
+ } else if (m_pos.x() + m_radius > width()) {
+ m_direction.setX(-m_direction.x());
+ m_pos.setX(width() - m_radius);
+ }
+
+ if (m_pos.y() - m_radius < 0) {
+ m_direction.setY(-m_direction.y());
+ m_pos.setY(m_radius);
+ } else if (m_pos.y() + m_radius > height()) {
+ m_direction.setY(-m_direction.y());
+ m_pos.setY(height() - m_radius);
+ }
+
+#ifdef QT_OPENGL_SUPPORT
+ if (usesOpenGL()) {
+ update();
+ } else
+#endif
+ {
+ QRect rectAfter = circle_bounds(m_pos, m_radius, m_fontSize);
+ update(rectAfter | rectBefore);
+ QApplication::syncX();
+ }
+ }
+// else if (e->timerId() == m_fpsTimer.timerId()) {
+// printf("fps: %d\n", m_fpsCounter);
+// emit frameRate(m_fpsCounter);
+// m_fpsCounter = 0;
+
+// }
+}
+
+void PathDeformRenderer::mousePressEvent(QMouseEvent *e)
+{
+ setDescriptionEnabled(false);
+
+ m_repaintTimer.stop();
+ m_offset = QPointF();
+ if (QLineF(m_pos, e->pos()).length() <= m_radius)
+ m_offset = m_pos - e->pos();
+
+ m_mousePress = e->pos();
+
+ // If we're not running in small screen mode, always assume we're dragging
+ m_mouseDrag = !m_smallScreen;
+
+ mouseMoveEvent(e);
+}
+
+void PathDeformRenderer::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (e->buttons() == Qt::NoButton && m_animated) {
+ m_repaintTimer.start(10, this);
+ m_repaintTracker.start();
+ }
+
+ if (!m_mouseDrag && m_smallScreen)
+ emit clicked();
+}
+
+void PathDeformRenderer::mouseMoveEvent(QMouseEvent *e)
+{
+ if (!m_mouseDrag && (QLineF(m_mousePress, e->pos()).length() > 25.0) )
+ m_mouseDrag = true;
+
+ if (m_mouseDrag) {
+ QRect rectBefore = circle_bounds(m_pos, m_radius, m_fontSize);
+ if (e->type() == QEvent::MouseMove) {
+ QLineF line(m_pos, e->pos() + m_offset);
+ line.setLength(line.length() * .1);
+ QPointF dir(line.dx(), line.dy());
+ m_direction = (m_direction + dir) / 2;
+ }
+ m_pos = e->pos() + m_offset;
+#ifdef QT_OPENGL_SUPPORT
+ if (usesOpenGL()) {
+ update();
+ } else
+#endif
+ {
+ QRect rectAfter = circle_bounds(m_pos, m_radius, m_fontSize);
+ update(rectBefore | rectAfter);
+ }
+ }
+}
+
+QPainterPath PathDeformRenderer::lensDeform(const QPainterPath &source, const QPointF &offset)
+{
+ QPainterPath path;
+ path.addPath(source);
+
+ qreal flip = m_intensity / qreal(100);
+
+ for (int i=0; i<path.elementCount(); ++i) {
+ const QPainterPath::Element &e = path.elementAt(i);
+
+ qreal x = e.x + offset.x();
+ qreal y = e.y + offset.y();
+
+ qreal dx = x - m_pos.x();
+ qreal dy = y - m_pos.y();
+ qreal len = m_radius - qSqrt(dx * dx + dy * dy);
+
+ if (len > 0) {
+ path.setElementPositionAt(i,
+ x + flip * dx * len / m_radius,
+ y + flip * dy * len / m_radius);
+ } else {
+ path.setElementPositionAt(i, x, y);
+ }
+
+ }
+
+ return path;
+}
+
+
+void PathDeformRenderer::paint(QPainter *painter)
+{
+ int pad_x = 5;
+ int pad_y = 5;
+
+ int skip_x = qRound(m_pathBounds.width() + pad_x + m_fontSize/2);
+ int skip_y = qRound(m_pathBounds.height() + pad_y);
+
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(Qt::black);
+
+ QRectF clip(painter->clipPath().boundingRect());
+
+ int overlap = pad_x / 2;
+
+ for (int start_y=0; start_y < height(); start_y += skip_y) {
+
+ if (start_y > clip.bottom())
+ break;
+
+ int start_x = -overlap;
+ for (; start_x < width(); start_x += skip_x) {
+
+ if (start_y + skip_y >= clip.top() &&
+ start_x + skip_x >= clip.left() &&
+ start_x <= clip.right()) {
+ for (int i=0; i<m_paths.size(); ++i) {
+ QPainterPath path = lensDeform(m_paths[i], QPointF(start_x, start_y));
+ painter->drawPath(path);
+ }
+ }
+ }
+ overlap = skip_x - (start_x - width());
+
+ }
+
+ if (preferImage()) {
+ painter->drawImage(m_pos - QPointF(m_radius + LENS_EXTENT, m_radius + LENS_EXTENT),
+ m_lens_image);
+ } else {
+ painter->drawPixmap(m_pos - QPointF(m_radius + LENS_EXTENT, m_radius + LENS_EXTENT),
+ m_lens_pixmap);
+ }
+}
+
+
+
+void PathDeformRenderer::setRadius(int radius)
+{
+ qreal max = qMax(m_radius, (qreal)radius);
+ m_radius = radius;
+ generateLensPixmap();
+ if (!m_animated || m_radius < max) {
+#ifdef QT_OPENGL_SUPPORT
+ if (usesOpenGL()) {
+ update();
+ } else
+#endif
+ {
+ update(circle_bounds(m_pos, max, m_fontSize));
+ }
+ }
+}
+
+void PathDeformRenderer::setIntensity(int intensity)
+{
+ m_intensity = intensity;
+ if (!m_animated) {
+#ifdef QT_OPENGL_SUPPORT
+ if (usesOpenGL()) {
+ update();
+ } else
+#endif
+ {
+ update(circle_bounds(m_pos, m_radius, m_fontSize));
+ }
+ }
+}
diff --git a/demos/deform/pathdeform.h b/demos/deform/pathdeform.h
new file mode 100644
index 0000000..45edb26
--- /dev/null
+++ b/demos/deform/pathdeform.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PATHDEFORM_H
+#define PATHDEFORM_H
+
+#include "arthurwidgets.h"
+
+#include <QPainterPath>
+#include <QBasicTimer>
+#include <QDateTime>
+
+class PathDeformRenderer : public ArthurFrame
+{
+ Q_OBJECT
+ Q_PROPERTY(bool animated READ animated WRITE setAnimated)
+ Q_PROPERTY(int radius READ radius WRITE setRadius)
+ Q_PROPERTY(int fontSize READ fontSize WRITE setFontSize)
+ Q_PROPERTY(int intensity READ intensity WRITE setIntensity)
+ Q_PROPERTY(QString text READ text WRITE setText)
+
+public:
+ PathDeformRenderer(QWidget *widget, bool smallScreen = false);
+
+ void paint(QPainter *painter);
+
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void timerEvent(QTimerEvent *e);
+
+ QSize sizeHint() const { return QSize(600, 500); }
+
+ bool animated() const { return m_animated; }
+ int radius() const { return int(m_radius); }
+ int fontSize() const { return m_fontSize; }
+ int intensity() const { return int(m_intensity); }
+ QString text() const { return m_text; }
+
+public slots:
+ void setRadius(int radius);
+ void setFontSize(int fontSize) { m_fontSize = fontSize; setText(m_text); }
+ void setText(const QString &text);
+ void setIntensity(int intensity);
+
+ void setAnimated(bool animated);
+
+signals:
+ void clicked();
+// void frameRate(double fps);
+
+private:
+ void generateLensPixmap();
+ QPainterPath lensDeform(const QPainterPath &source, const QPointF &offset);
+
+ QBasicTimer m_repaintTimer;
+// QBasicTimer m_fpsTimer;
+// int m_fpsCounter;
+ QTime m_repaintTracker;
+
+ QVector<QPainterPath> m_paths;
+ QVector<QPointF> m_advances;
+ QRectF m_pathBounds;
+ QString m_text;
+
+ QPixmap m_lens_pixmap;
+ QImage m_lens_image;
+
+ int m_fontSize;
+ bool m_animated;
+
+ qreal m_intensity;
+ qreal m_radius;
+ QPointF m_pos;
+ QPointF m_offset;
+ QPointF m_direction;
+ QPointF m_mousePress;
+ bool m_mouseDrag;
+ bool m_smallScreen;
+};
+
+class PathDeformControls : public QWidget
+{
+ Q_OBJECT
+public:
+ PathDeformControls(QWidget *parent, PathDeformRenderer* renderer, bool smallScreen);
+signals:
+ void okPressed();
+ void quitPressed();
+private:
+ PathDeformRenderer* m_renderer;
+ void layoutForDesktop();
+ void layoutForSmallScreen();
+private slots:
+ void emitQuitSignal();
+ void emitOkSignal();
+};
+
+class PathDeformWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ PathDeformWidget(QWidget *parent, bool smallScreen);
+ void setStyle ( QStyle * style );
+
+private:
+ PathDeformRenderer *m_renderer;
+ PathDeformControls *m_controls;
+
+private slots:
+ void showControls();
+ void hideControls();
+};
+
+#endif // PATHDEFORM_H
diff --git a/demos/deform/pathdeform.html b/demos/deform/pathdeform.html
new file mode 100644
index 0000000..b3f63a8
--- /dev/null
+++ b/demos/deform/pathdeform.html
@@ -0,0 +1,24 @@
+<html>
+<center>
+<h2>Vector deformation</h2>
+</center>
+
+<p>This demo shows how to use advanced vector techniques to draw text
+using a <code>QPainterPath</code>.</p>
+
+<p>We define a vector deformation field in the shape of a lens and apply
+this to all points in a path. This means that what is rendered on
+screen is not pixel manipulation, but modified vector representations of
+the glyphs themselves. This is visible from the high quality of the
+antialiased edges for the deformed glyphs.</p>
+
+<p>To get a fairly complex path we allow the user to type in text and
+convert the text to paths. This is done using the
+<code>QPainterPath::addText()</code> function.</p>
+
+<p>The lens is drawn using a single call to <code>drawEllipse()</code>, using
+a <code>QRadialGradient</code> to fill it with a specialized color table,
+giving the effect of the Sun's reflection and a drop shadow. The lens
+is cached as a pixmap for better performance.</p>
+
+</html>
diff --git a/demos/demobase.pri b/demos/demobase.pri
new file mode 100644
index 0000000..c0bba64
--- /dev/null
+++ b/demos/demobase.pri
@@ -0,0 +1 @@
+symbian:RSS_RULES = "group_name=\"QtDemos\";" \ No newline at end of file
diff --git a/demos/demos.pro b/demos/demos.pro
new file mode 100644
index 0000000..1c98b9e
--- /dev/null
+++ b/demos/demos.pro
@@ -0,0 +1,80 @@
+TEMPLATE = subdirs
+SUBDIRS = \
+ demos_shared \
+ demos_deform \
+ demos_gradients \
+ demos_pathstroke \
+ demos_affine \
+ demos_composition \
+ demos_books \
+ demos_interview \
+ demos_mainwindow \
+ demos_spreadsheet \
+ demos_textedit \
+ demos_chip \
+ demos_embeddeddialogs \
+ demos_undo
+
+symbian: SUBDIRS = \
+ demos_shared \
+ demos_deform \
+ demos_pathstroke
+
+contains(QT_CONFIG, opengl):!contains(QT_CONFIG, opengles1):!contains(QT_CONFIG, opengles1cl):!contains(QT_CONFIG, opengles2):{
+SUBDIRS += demos_boxes
+}
+
+mac*: SUBDIRS += demos_macmainwindow
+wince*|symbian|embedded: SUBDIRS += embedded
+
+!contains(QT_EDITION, Console):!cross_compile:!embedded:!wince*:SUBDIRS += demos_arthurplugin
+
+!cross_compile:{
+contains(QT_BUILD_PARTS, tools):{
+!wince*:SUBDIRS += demos_sqlbrowser demos_qtdemo
+wince*: SUBDIRS += demos_sqlbrowser
+}
+}
+contains(QT_CONFIG, phonon)!static:SUBDIRS += demos_mediaplayer
+contains(QT_CONFIG, webkit):contains(QT_CONFIG, svg):SUBDIRS += demos_browser
+
+# install
+sources.files = README *.pro
+sources.path = $$[QT_INSTALL_DEMOS]
+INSTALLS += sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
+demos_chip.subdir = chip
+demos_embeddeddialogs.subdir = embeddeddialogs
+demos_shared.subdir = shared
+demos_deform.subdir = deform
+demos_gradients.subdir = gradients
+demos_pathstroke.subdir = pathstroke
+demos_affine.subdir = affine
+demos_composition.subdir = composition
+demos_books.subdir = books
+demos_interview.subdir = interview
+demos_macmainwindow.subdir = macmainwindow
+demos_mainwindow.subdir = mainwindow
+demos_spreadsheet.subdir = spreadsheet
+demos_textedit.subdir = textedit
+demos_arthurplugin.subdir = arthurplugin
+demos_sqlbrowser.subdir = sqlbrowser
+demos_undo.subdir = undo
+demos_qtdemo.subdir = qtdemo
+demos_mediaplayer.subdir = mediaplayer
+
+demos_browser.subdir = browser
+
+demos_boxes.subdir = boxes
+
+#CONFIG += ordered
+!ordered {
+ demos_affine.depends = demos_shared
+ demos_deform.depends = demos_shared
+ demos_gradients.depends = demos_shared
+ demos_composition.depends = demos_shared
+ demos_arthurplugin.depends = demos_shared
+ demos_pathstroke.depends = demos_shared
+}
diff --git a/demos/embedded/desktopservices/contenttab.cpp b/demos/embedded/desktopservices/contenttab.cpp
new file mode 100644
index 0000000..1abb051
--- /dev/null
+++ b/demos/embedded/desktopservices/contenttab.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+// EXTERNAL INCLUDES
+#include <QKeyEvent>
+#include <QListWidget>
+#include <QVBoxLayout>
+#include <QFileInfoList>
+#include <QListWidgetItem>
+
+// INTERNAL INCLUDES
+
+// CLASS HEADER
+#include "contenttab.h"
+
+
+// CONSTRUCTORS & DESTRUCTORS
+ContentTab::ContentTab(QWidget *parent) :
+ QListWidget(parent)
+{
+ setDragEnabled(false);
+ setIconSize(QSize(45, 45));
+}
+
+ContentTab::~ContentTab()
+{
+}
+
+// NEW PUBLIC METHODS
+void ContentTab::init(const QDesktopServices::StandardLocation &location,
+ const QString &icon)
+{
+ setContentDir(location);
+ setIcon(icon);
+
+ connect(this, SIGNAL(itemClicked(QListWidgetItem *)),
+ this, SLOT(openItem(QListWidgetItem *)));
+
+ populateListWidget();
+}
+
+// NEW PROTECTED METHODS
+void ContentTab::setContentDir(const QDesktopServices::StandardLocation &location)
+{
+ m_ContentDir.setPath(QDesktopServices::storageLocation(location));
+}
+
+void ContentTab::setIcon(const QString &icon)
+{
+ m_Icon = QIcon(icon);
+}
+
+void ContentTab::populateListWidget()
+{
+ QFileInfoList fileList = m_ContentDir.entryInfoList(QStringList(), QDir::Files, QDir::Time);
+ foreach(QFileInfo item, fileList) {
+ new QListWidgetItem(m_Icon, itemName(item), this);
+ }
+}
+
+QString ContentTab::itemName(const QFileInfo &item)
+{
+ return QString(item.baseName() + "." + item.completeSuffix());
+}
+
+QUrl ContentTab::itemUrl(QListWidgetItem *item)
+{
+ return QUrl("file:///" + m_ContentDir.absolutePath() + "/" + item->text());
+}
+
+void ContentTab::keyPressEvent(QKeyEvent *event)
+{
+ switch(event->key()) {
+ case Qt::Key_Up:
+ if(currentRow() == 0) {
+ setCurrentRow(count()-1);
+ } else {
+ setCurrentRow(currentRow()-1);
+ }
+ break;
+ case Qt::Key_Down:
+ if(currentRow() == (count()-1)) {
+ setCurrentRow(0);
+ } else {
+ setCurrentRow(currentRow()+1);
+ }
+ break;
+ case Qt::Key_Select:
+ openItem(currentItem());
+ default:
+ QListWidget::keyPressEvent(event);
+ break;
+ }
+}
+
+// NEW SLOTS
+void ContentTab::openItem(QListWidgetItem *item)
+{
+ QDesktopServices::openUrl(itemUrl(item));
+}
+
+// End of File
diff --git a/demos/embedded/desktopservices/contenttab.h b/demos/embedded/desktopservices/contenttab.h
new file mode 100644
index 0000000..bfbb044
--- /dev/null
+++ b/demos/embedded/desktopservices/contenttab.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CONTENTTAB_H_
+#define CONTENTTAB_H_
+
+// EXTERNAL INCLUDES
+#include <QDir>
+#include <QUrl>
+#include <QIcon>
+#include <QFileInfo>
+#include <QListWidget>
+#include <QDesktopServices>
+
+// INTERNAL INCLUDES
+
+// FORWARD DECLARATIONS
+class QListWidgetItem;
+
+// CLASS DECLARATION
+
+/**
+* ContentTab class.
+*
+* This class implements general purpose tab for media files.
+*/
+class ContentTab : public QListWidget
+{
+ Q_OBJECT
+
+public: // Constructors & Destructors
+ ContentTab(QWidget *parent);
+ virtual ~ContentTab();
+
+public: // New Methods
+ virtual void init(const QDesktopServices::StandardLocation &location,
+ const QString &icon);
+
+protected: // New Methods
+ virtual void setContentDir(const QDesktopServices::StandardLocation &location);
+ virtual void setIcon(const QString &icon);
+ virtual void populateListWidget();
+ virtual QString itemName(const QFileInfo &item);
+ virtual QUrl itemUrl(QListWidgetItem *item);
+
+protected:
+ void keyPressEvent(QKeyEvent *event);
+
+public slots: // New Slots
+ virtual void openItem(QListWidgetItem *item);
+
+protected: // Owned variables
+ QDir m_ContentDir;
+ QIcon m_Icon;
+};
+
+
+#endif // CONTENTTAB_H_
+
+// End of File
diff --git a/demos/embedded/desktopservices/data/Explosion.wav b/demos/embedded/desktopservices/data/Explosion.wav
new file mode 100644
index 0000000..7b140b1
--- /dev/null
+++ b/demos/embedded/desktopservices/data/Explosion.wav
Binary files differ
diff --git a/demos/embedded/desktopservices/data/designer.png b/demos/embedded/desktopservices/data/designer.png
new file mode 100644
index 0000000..0988fce
--- /dev/null
+++ b/demos/embedded/desktopservices/data/designer.png
Binary files differ
diff --git a/demos/embedded/desktopservices/data/monkey_on_64x64.png b/demos/embedded/desktopservices/data/monkey_on_64x64.png
new file mode 100644
index 0000000..990f604
--- /dev/null
+++ b/demos/embedded/desktopservices/data/monkey_on_64x64.png
Binary files differ
diff --git a/demos/embedded/desktopservices/data/sax.mp3 b/demos/embedded/desktopservices/data/sax.mp3
new file mode 100644
index 0000000..0a078b1
--- /dev/null
+++ b/demos/embedded/desktopservices/data/sax.mp3
Binary files differ
diff --git a/demos/embedded/desktopservices/desktopservices.pro b/demos/embedded/desktopservices/desktopservices.pro
new file mode 100644
index 0000000..32cb6d9
--- /dev/null
+++ b/demos/embedded/desktopservices/desktopservices.pro
@@ -0,0 +1,23 @@
+TEMPLATE = app
+TARGET =
+INCLUDEPATH += .
+
+HEADERS += desktopwidget.h contenttab.h linktab.h
+SOURCES += desktopwidget.cpp contenttab.cpp linktab.cpp main.cpp
+
+RESOURCES += desktopservices.qrc
+
+music.sources = data/*.mp3 data/*.wav
+music.path = /data/sounds/
+
+image.sources = data/*.png
+image.path = /data/images/
+
+DEPLOYMENT += music image
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
+symbian {
+ TARGET.UID3 = 0xA000C611
+ ICON = ./resources/heart.svg
+}
diff --git a/demos/embedded/desktopservices/desktopservices.qrc b/demos/embedded/desktopservices/desktopservices.qrc
new file mode 100644
index 0000000..d36205d
--- /dev/null
+++ b/demos/embedded/desktopservices/desktopservices.qrc
@@ -0,0 +1,8 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>resources/music.png</file>
+ <file>resources/photo.png</file>
+ <file>resources/browser.png</file>
+ <file>resources/message.png</file>
+</qresource>
+</RCC>
diff --git a/demos/embedded/desktopservices/desktopwidget.cpp b/demos/embedded/desktopservices/desktopwidget.cpp
new file mode 100644
index 0000000..17243cf
--- /dev/null
+++ b/demos/embedded/desktopservices/desktopwidget.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+// EXTERNAL INCLUDES
+#include <QTabWidget>
+#include <QVBoxLayout>
+#include <QDesktopServices>
+
+// INTERNAL INCLUDES
+#include "linktab.h"
+#include "contenttab.h"
+
+// CLASS HEADER
+#include "desktopwidget.h"
+
+// CONSTRUCTORS & DESTRUCTORS
+DesktopWidget::DesktopWidget(QWidget *parent) : QWidget(parent)
+
+{
+ QTabWidget *tabWidget = new QTabWidget(this);
+
+ // Images
+ ContentTab* imageTab = new ContentTab(tabWidget);
+ imageTab->init(QDesktopServices::PicturesLocation, ":/resources/photo.png");
+ tabWidget->addTab(imageTab, tr("Images"));
+
+ // Music
+ ContentTab* musicTab = new ContentTab(tabWidget);
+ musicTab->init(QDesktopServices::MusicLocation, ":/resources/music.png");
+ tabWidget->addTab(musicTab, tr("Music"));
+
+ // Links
+ LinkTab* othersTab = new LinkTab(tabWidget);;
+ // Given icon file will be overriden by LinkTab
+ othersTab->init(QDesktopServices::PicturesLocation, "");
+ tabWidget->addTab(othersTab, tr("Links"));
+
+ // Layout
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addWidget(tabWidget);
+ setLayout(layout);
+}
+
+DesktopWidget::~DesktopWidget()
+{
+}
+
+// End of file
diff --git a/demos/embedded/desktopservices/desktopwidget.h b/demos/embedded/desktopservices/desktopwidget.h
new file mode 100644
index 0000000..5b74e48
--- /dev/null
+++ b/demos/embedded/desktopservices/desktopwidget.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DESKTOPWIDGET_H_
+#define DESKTOPWIDGET_H_
+
+// EXTERNAL INCLUDES
+#include <QWidget>
+
+// INTERNAL INCLUDES
+
+// FORWARD DECLARATIONS
+class QTabWidget;
+
+// CLASS DECLARATION
+/**
+* DesktopWidget class.
+*
+* Implements the main top level widget for QDesktopServices demo app.
+*/
+class DesktopWidget : public QWidget
+{
+ Q_OBJECT
+
+public: // Constructors & Destructors
+ DesktopWidget(QWidget *parent);
+ ~DesktopWidget();
+
+};
+
+#endif // DESKTOPWIDGET_H_
+
+// End of file
diff --git a/demos/embedded/desktopservices/linktab.cpp b/demos/embedded/desktopservices/linktab.cpp
new file mode 100644
index 0000000..0d5bea7
--- /dev/null
+++ b/demos/embedded/desktopservices/linktab.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+// EXTERNAL INCLUDES
+#include <QUrl>
+#include <QListWidgetItem>
+
+// INTERNAL INCLUDES
+
+// CLASS HEADER
+#include "linktab.h"
+
+LinkTab::LinkTab(QWidget *parent) :
+ ContentTab(parent)
+{
+}
+
+LinkTab::~LinkTab()
+{
+}
+
+void LinkTab::populateListWidget()
+{
+ m_WebItem = new QListWidgetItem(QIcon(":/resources/browser.png"), tr("Launch Browser"), this);
+ m_MailToItem = new QListWidgetItem(QIcon(":/resources/message.png"), tr("New e-mail"), this);
+}
+
+QUrl LinkTab::itemUrl(QListWidgetItem *item)
+{
+ if(m_WebItem == item) {
+ return QUrl(tr("http://www.qtsoftware.com"));
+ } else if(m_MailToItem == item) {
+ return QUrl(tr("mailto:qts60-feedback@trolltech.com?subject=QtS60 feedback&body=Hello"));
+ } else {
+ // We should never endup here
+ Q_ASSERT(false);
+ return QUrl();
+ }
+}
+
+// End of file
diff --git a/demos/embedded/desktopservices/linktab.h b/demos/embedded/desktopservices/linktab.h
new file mode 100644
index 0000000..02ad494
--- /dev/null
+++ b/demos/embedded/desktopservices/linktab.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LINKTAB_H_
+#define LINKTAB_H_
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include "contenttab.h"
+
+// FORWARD DECLARATIONS
+class QWidget;
+class QListWidgetItem;
+
+// CLASS DECLARATION
+
+/**
+* LinkTab class.
+*
+* This class implements tab for opening http and mailto links.
+*/
+class LinkTab : public ContentTab
+{
+ Q_OBJECT
+
+public: // Constructors & Destructors
+ LinkTab(QWidget *parent);
+ ~LinkTab();
+
+protected: // Derived Methods
+ virtual void populateListWidget();
+ virtual QUrl itemUrl(QListWidgetItem *item);
+
+private: // Used variables
+ QListWidgetItem *m_WebItem;
+ QListWidgetItem *m_MailToItem;
+
+private: // Owned variables
+
+};
+
+#endif // CONTENTTAB_H_
+
+// End of File
diff --git a/demos/embedded/desktopservices/main.cpp b/demos/embedded/desktopservices/main.cpp
new file mode 100644
index 0000000..32e22ae
--- /dev/null
+++ b/demos/embedded/desktopservices/main.cpp
@@ -0,0 +1,26 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include "desktopwidget.h"
+
+int main(int argc, char *argv[])
+{
+ Q_INIT_RESOURCE(desktopservices);
+
+ QApplication app(argc, argv);
+ DesktopWidget* myWidget = new DesktopWidget(0);
+ myWidget->showMaximized();
+
+ return app.exec();
+}
+
+// End of file
diff --git a/demos/embedded/desktopservices/resources/browser.png b/demos/embedded/desktopservices/resources/browser.png
new file mode 100644
index 0000000..28561e1
--- /dev/null
+++ b/demos/embedded/desktopservices/resources/browser.png
Binary files differ
diff --git a/demos/embedded/desktopservices/resources/heart.svg b/demos/embedded/desktopservices/resources/heart.svg
new file mode 100644
index 0000000..ba5f050
--- /dev/null
+++ b/demos/embedded/desktopservices/resources/heart.svg
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) --><svg viewBox="100 200 550 500" height="595.27559pt" id="svg1" inkscape:version="0.40+cvs" sodipodi:docbase="C:\Documents and Settings\Jon Phillips\My Documents\projects\clipart-project\submissions" sodipodi:docname="heart-left-highlight.svg" sodipodi:version="0.32" width="595.27559pt" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg">
+<metadata>
+<rdf:RDF xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<cc:Work rdf:about="">
+<dc:title>Heart Left-Highlight</dc:title>
+<dc:description>This is a normal valentines day heart.</dc:description>
+<dc:subject>
+<rdf:Bag>
+<rdf:li>holiday</rdf:li>
+<rdf:li>valentines</rdf:li>
+<rdf:li></rdf:li>
+<rdf:li>valentine</rdf:li>
+<rdf:li>hash(0x8a091c0)</rdf:li>
+<rdf:li>hash(0x8a0916c)</rdf:li>
+<rdf:li>signs_and_symbols</rdf:li>
+<rdf:li>hash(0x8a091f0)</rdf:li>
+<rdf:li>day</rdf:li>
+</rdf:Bag>
+</dc:subject>
+<dc:publisher>
+<cc:Agent rdf:about="http://www.openclipart.org">
+<dc:title>Jon Phillips</dc:title>
+</cc:Agent>
+</dc:publisher>
+<dc:creator>
+<cc:Agent>
+<dc:title>Jon Phillips</dc:title>
+</cc:Agent>
+</dc:creator>
+<dc:rights>
+<cc:Agent>
+<dc:title>Jon Phillips</dc:title>
+</cc:Agent>
+</dc:rights>
+<dc:date></dc:date>
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<cc:license rdf:resource="http://web.resource.org/cc/PublicDomain"/>
+<dc:language>en</dc:language>
+</cc:Work>
+<cc:License rdf:about="http://web.resource.org/cc/PublicDomain">
+<cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
+<cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/>
+<cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
+</cc:License>
+</rdf:RDF>
+</metadata>
+<defs id="defs3"/>
+<sodipodi:namedview bordercolor="#666666" borderopacity="1.0" id="base" inkscape:current-layer="layer1" inkscape:cx="549.40674" inkscape:cy="596.00159" inkscape:document-units="px" inkscape:guide-bbox="true" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:window-height="615" inkscape:window-width="866" inkscape:window-x="88" inkscape:window-y="116" inkscape:zoom="0.35000000" pagecolor="#ffffff" showguides="true"/>
+<g id="layer1" inkscape:groupmode="layer" inkscape:label="Layer 1">
+<path d="M 263.41570,235.14588 C 197.17570,235.14588 143.41575,288.90587 143.41575,355.14588 C 143.41575,489.90139 279.34890,525.23318 371.97820,658.45392 C 459.55244,526.05056 600.54070,485.59932 600.54070,355.14588 C 600.54070,288.90588 546.78080,235.14587 480.54070,235.14588 C 432.49280,235.14588 391.13910,263.51631 371.97820,304.33338 C 352.81740,263.51630 311.46370,235.14587 263.41570,235.14588 z " id="path7" sodipodi:nodetypes="ccccccc" style="fill:#e60000;fill-opacity:1.0000000;stroke:#000000;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/>
+<path d="M 265.00000,253.59375 C 207.04033,253.59375 160.00000,300.63407 160.00000,358.59375 C 160.00000,476.50415 278.91857,507.43251 359.96875,624.00000 C 366.52868,614.08205 220.00000,478.47309 220.00000,378.59375 C 220.00000,320.63407 267.04033,273.59375 325.00000,273.59375 C 325.50453,273.59375 325.99718,273.64912 326.50000,273.65625 C 309.22436,261.07286 288.00557,253.59374 265.00000,253.59375 z " id="path220" sodipodi:nodetypes="ccccccc" style="fill:#e6e6e6;fill-opacity:0.64556962;stroke:none;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/>
+</g>
+</svg>
diff --git a/demos/embedded/desktopservices/resources/message.png b/demos/embedded/desktopservices/resources/message.png
new file mode 100644
index 0000000..e30052b
--- /dev/null
+++ b/demos/embedded/desktopservices/resources/message.png
Binary files differ
diff --git a/demos/embedded/desktopservices/resources/music.png b/demos/embedded/desktopservices/resources/music.png
new file mode 100644
index 0000000..11a57bb
--- /dev/null
+++ b/demos/embedded/desktopservices/resources/music.png
Binary files differ
diff --git a/demos/embedded/desktopservices/resources/photo.png b/demos/embedded/desktopservices/resources/photo.png
new file mode 100644
index 0000000..5ba15c1
--- /dev/null
+++ b/demos/embedded/desktopservices/resources/photo.png
Binary files differ
diff --git a/demos/embedded/embedded.pro b/demos/embedded/embedded.pro
new file mode 100644
index 0000000..8214dd3
--- /dev/null
+++ b/demos/embedded/embedded.pro
@@ -0,0 +1,16 @@
+TEMPLATE = subdirs
+SUBDIRS = styledemo
+
+contains(QT_CONFIG, svg) {
+ SUBDIRS += embeddedsvgviewer \
+ fluidlauncher \
+ desktopservices
+}
+
+# install
+sources.files = README *.pro
+sources.path = $$[QT_INSTALL_DEMOS]/embedded
+INSTALLS += sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
diff --git a/demos/embedded/embeddedsvgviewer/embeddedsvgviewer.cpp b/demos/embedded/embeddedsvgviewer/embeddedsvgviewer.cpp
new file mode 100644
index 0000000..1bd99c9
--- /dev/null
+++ b/demos/embedded/embeddedsvgviewer/embeddedsvgviewer.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QPainter>
+#include <QApplication>
+
+#include "embeddedsvgviewer.h"
+
+
+
+EmbeddedSvgViewer::EmbeddedSvgViewer(const QString &filePath)
+{
+ qApp->setStyleSheet(" QSlider:vertical { width: 50px; } \
+ QSlider::groove:vertical { border: 1px solid black; border-radius: 3px; width: 6px; } \
+ QSlider::handle:vertical { height: 25px; margin: 0 -22px; image: url(':/files/v-slider-handle.svg'); } \
+ ");
+
+ m_renderer = new QSvgRenderer(filePath);
+ m_imageSize = m_renderer->viewBox().size();
+
+ m_viewBoxCenter = (QPointF(m_imageSize.width() / qreal(2.0), m_imageSize.height() / qreal(2.0)));
+
+ m_zoomSlider = new QSlider(Qt::Vertical, this);
+ m_zoomSlider->setMaximum(150);
+ m_zoomSlider->setMinimum(1);
+
+ connect(m_zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(setZoom(int)));
+ m_zoomSlider->setValue(100);
+
+ m_quitButton = new QPushButton("Quit", this);
+
+ connect(m_quitButton, SIGNAL(pressed()), QApplication::instance(), SLOT(quit()));
+
+ if (m_renderer->animated())
+ connect(m_renderer, SIGNAL(repaintNeeded()), this, SLOT(update()));
+
+}
+
+void EmbeddedSvgViewer::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event)
+ QPainter painter(this);
+ m_renderer->setViewBox(m_viewBox);
+ m_renderer->render(&painter);
+}
+
+
+void EmbeddedSvgViewer::mouseMoveEvent ( QMouseEvent * event )
+{
+ int incX = int((event->globalX() - m_mousePress.x()) * m_imageScale);
+ int incY = int((event->globalY() - m_mousePress.y()) * m_imageScale);
+
+ QPointF newCenter;
+ newCenter.setX(m_viewBoxCenterOnMousePress.x() - incX);
+ newCenter.setY(m_viewBoxCenterOnMousePress.y() - incY);
+
+ QRectF newViewBox = getViewBox(newCenter);
+
+
+ // Do a bounded move on the horizontal:
+ if ( (newViewBox.left() >= m_viewBoxBounds.left()) &&
+ (newViewBox.right() <= m_viewBoxBounds.right()) )
+ {
+ m_viewBoxCenter.setX(newCenter.x());
+ m_viewBox.setLeft(newViewBox.left());
+ m_viewBox.setRight(newViewBox.right());
+ }
+
+ // do a bounded move on the vertical:
+ if ( (newViewBox.top() >= m_viewBoxBounds.top()) &&
+ (newViewBox.bottom() <= m_viewBoxBounds.bottom()) )
+ {
+ m_viewBoxCenter.setY(newCenter.y());
+ m_viewBox.setTop(newViewBox.top());
+ m_viewBox.setBottom(newViewBox.bottom());
+ }
+
+ update();
+}
+
+void EmbeddedSvgViewer::mousePressEvent ( QMouseEvent * event )
+{
+ m_viewBoxCenterOnMousePress = m_viewBoxCenter;
+ m_mousePress = event->globalPos();
+}
+
+
+QRectF EmbeddedSvgViewer::getViewBox(QPointF viewBoxCenter)
+{
+ QRectF result;
+ result.setLeft(viewBoxCenter.x() - (m_viewBoxSize.width() / 2));
+ result.setTop(viewBoxCenter.y() - (m_viewBoxSize.height() / 2));
+ result.setRight(viewBoxCenter.x() + (m_viewBoxSize.width() / 2));
+ result.setBottom(viewBoxCenter.y() + (m_viewBoxSize.height() / 2));
+ return result;
+}
+
+void EmbeddedSvgViewer::updateImageScale()
+{
+ m_imageScale = qMax( (qreal)m_imageSize.width() / (qreal)width(),
+ (qreal)m_imageSize.height() / (qreal)height())*m_zoomLevel;
+
+ m_viewBoxSize.setWidth((qreal)width() * m_imageScale);
+ m_viewBoxSize.setHeight((qreal)height() * m_imageScale);
+}
+
+
+void EmbeddedSvgViewer::resizeEvent ( QResizeEvent * event )
+{
+ qreal origZoom = m_zoomLevel;
+
+ // Get the new bounds:
+ m_zoomLevel = 1.0;
+ updateImageScale();
+ m_viewBoxBounds = getViewBox(QPointF(m_imageSize.width() / 2.0, m_imageSize.height() / 2.0));
+
+ m_zoomLevel = origZoom;
+ updateImageScale();
+ m_viewBox = getViewBox(m_viewBoxCenter);
+
+ QRect sliderRect;
+ sliderRect.setLeft(width() - m_zoomSlider->sizeHint().width());
+ sliderRect.setRight(width());
+ sliderRect.setTop(height()/4);
+ sliderRect.setBottom(height() - (height()/4));
+ m_zoomSlider->setGeometry(sliderRect);
+}
+
+
+void EmbeddedSvgViewer::setZoom(int newZoom)
+{
+ m_zoomLevel = qreal(newZoom) / qreal(100);
+
+ updateImageScale();
+ m_viewBox = getViewBox(m_viewBoxCenter);
+
+ update();
+}
+
+
+
+
+
diff --git a/demos/embedded/embeddedsvgviewer/embeddedsvgviewer.h b/demos/embedded/embeddedsvgviewer/embeddedsvgviewer.h
new file mode 100644
index 0000000..c0af3cf
--- /dev/null
+++ b/demos/embedded/embeddedsvgviewer/embeddedsvgviewer.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef EMBEDDED_SVG_VIEWER_H
+#define EMBEDDED_SVG_VIEWER_H
+
+#include <QWidget>
+#include <QString>
+#include <QSvgRenderer>
+#include <QSize>
+#include <QMouseEvent>
+#include <QSlider>
+#include <QPushButton>
+
+class EmbeddedSvgViewer : public QWidget
+{
+ Q_OBJECT
+public:
+ EmbeddedSvgViewer(const QString& filePath);
+ virtual void paintEvent(QPaintEvent *event);
+ void mouseMoveEvent ( QMouseEvent * event );
+ void mousePressEvent ( QMouseEvent * event );
+ void resizeEvent ( QResizeEvent * event );
+
+public slots:
+ void setZoom(int); // 100 <= newZoom < 0
+
+private:
+ QSvgRenderer* m_renderer;
+ QSlider* m_zoomSlider;
+ QPushButton* m_quitButton;
+ QSize m_imageSize;
+ qreal m_zoomLevel;
+ qreal m_imageScale; // How many Image coords 1 widget pixel is worth
+
+ QRectF m_viewBox;
+ QRectF m_viewBoxBounds;
+ QSizeF m_viewBoxSize;
+ QPointF m_viewBoxCenter;
+ QPointF m_viewBoxCenterOnMousePress;
+ QPoint m_mousePress;
+
+ void updateImageScale();
+ QRectF getViewBox(QPointF viewBoxCenter);
+};
+
+
+
+#endif
diff --git a/demos/embedded/embeddedsvgviewer/embeddedsvgviewer.pro b/demos/embedded/embeddedsvgviewer/embeddedsvgviewer.pro
new file mode 100644
index 0000000..51a04e7
--- /dev/null
+++ b/demos/embedded/embeddedsvgviewer/embeddedsvgviewer.pro
@@ -0,0 +1,21 @@
+TEMPLATE = app
+QT += svg
+
+# Input
+HEADERS += embeddedsvgviewer.h
+SOURCES += embeddedsvgviewer.cpp main.cpp
+RESOURCES += embeddedsvgviewer.qrc
+
+target.path = $$[QT_INSTALL_DEMOS]/embedded/embeddedsvgviewer
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.html *.svg files
+sources.path = $$[QT_INSTALL_DEMOS]/embedded/embeddedsvgviewer
+INSTALLS += target sources
+
+wince* {
+ DEPLOYMENT_PLUGIN += qsvg
+}
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
+symbian:TARGET.UID3 = 0xA000A640
+
diff --git a/demos/embedded/embeddedsvgviewer/embeddedsvgviewer.qrc b/demos/embedded/embeddedsvgviewer/embeddedsvgviewer.qrc
new file mode 100644
index 0000000..bb02118
--- /dev/null
+++ b/demos/embedded/embeddedsvgviewer/embeddedsvgviewer.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>files/v-slider-handle.svg</file>
+ <file>files/default.svg</file>
+</qresource>
+</RCC>
+
diff --git a/demos/embedded/embeddedsvgviewer/files/default.svg b/demos/embedded/embeddedsvgviewer/files/default.svg
new file mode 100644
index 0000000..c28a711
--- /dev/null
+++ b/demos/embedded/embeddedsvgviewer/files/default.svg
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="400px"
+ height="400px"
+ baseProfile="tiny"
+ id="svg8268"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ sodipodi:docname="simple2.svg"
+ sodipodi:docbase="/nfs/OpenMoko/SVGs"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <metadata
+ id="metadata8283">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8281" />
+ <sodipodi:namedview
+ inkscape:window-height="917"
+ inkscape:window-width="1324"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ inkscape:zoom="2.1452345"
+ inkscape:cx="185.25"
+ inkscape:cy="214.75"
+ inkscape:window-x="0"
+ inkscape:window-y="30"
+ inkscape:current-layer="svg8268" />
+ <g
+ stroke="DarkBlue"
+ stroke-width="10"
+ id="g8270">
+ <rect
+ fill="blue"
+ fill-opacity="0.5"
+ x="25"
+ y="25"
+ width="175"
+ height="175"
+ id="rect8272" />
+ </g>
+ <circle
+ cx="200"
+ cy="200"
+ r="75"
+ id="circle8274"
+ sodipodi:cx="200"
+ sodipodi:cy="200"
+ sodipodi:rx="75"
+ sodipodi:ry="75"
+ transform="translate(-26.104372,21.909027)"
+ style="fill:#ffff00;fill-opacity:0.5;stroke:#000000" />
+ <polygon
+ fill="green"
+ stroke="black"
+ fill-opacity="0.5"
+ stroke-width="1"
+ points="200,225 350,225 275,350"
+ id="polygon8276" />
+ <path
+ style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:0.50196081"
+ d="M 303.7037,50.705207 C 173.88522,56.588264 90.320951,92.710345 162.85059,120.82533 C 211.91719,139.84524 196.63811,214.12391 233.86243,192.59259 C 284.31755,163.4083 299.34345,193.75691 311.11111,187.30159 C 347.88407,167.12924 269.34382,134.85785 303.81608,114.5167 C 394.71183,60.881583 332.47907,46.043712 303.7037,50.705207 z "
+ id="path8289"
+ sodipodi:nodetypes="cssssc" />
+</svg>
diff --git a/demos/embedded/embeddedsvgviewer/files/v-slider-handle.svg b/demos/embedded/embeddedsvgviewer/files/v-slider-handle.svg
new file mode 100644
index 0000000..4ee87f8
--- /dev/null
+++ b/demos/embedded/embeddedsvgviewer/files/v-slider-handle.svg
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="50"
+ height="25"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ version="1.0"
+ sodipodi:docbase="/home/tcooksey/Projects/qt-4.4/demos/embedded/embeddedsvgviewer/files"
+ sodipodi:docname="v-slider-handle.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs4">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2158">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop2160" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop2162" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2158"
+ id="linearGradient2164"
+ x1="26.10779"
+ y1="9.1025448"
+ x2="26.10779"
+ y2="-0.01334004"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.9876687,0,0,2.5969342,0.3086332,-0.476397)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="12.256878"
+ inkscape:cx="42.920885"
+ inkscape:cy="4.2252457"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ width="50px"
+ height="25px"
+ inkscape:window-width="1282"
+ inkscape:window-height="879"
+ inkscape:window-x="137"
+ inkscape:window-y="30" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ style="fill:url(#linearGradient2164);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60153389px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 10.191803,24.254577 C 26.804559,24.254577 25.309299,24.303278 39.985656,24.303278 C 52.503796,24.303278 51.963217,0.91536797 40.722957,0.91536797 C 13.837108,0.91536797 16.298612,0.86901372 10.385089,0.86901372 C -2.0345215,0.86901372 -2.5249912,24.254577 10.191803,24.254577 z "
+ id="path2162"
+ sodipodi:nodetypes="csssc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:#868686;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path2166"
+ sodipodi:cx="9.4232807"
+ sodipodi:cy="13.169908"
+ sodipodi:rx="2.2436383"
+ sodipodi:ry="1.9580842"
+ d="M 9.4232808,15.127992 A 2.2436383,1.9580842 0 1 1 9.4232808,11.211823 L 9.4232807,13.169908 z"
+ sodipodi:start="1.5707963"
+ sodipodi:end="4.712389"
+ transform="matrix(4.3804554,0,0,2.228386,-25.247974,-16.463284)" />
+ </g>
+</svg>
diff --git a/demos/embedded/embeddedsvgviewer/main.cpp b/demos/embedded/embeddedsvgviewer/main.cpp
new file mode 100644
index 0000000..80f92d6
--- /dev/null
+++ b/demos/embedded/embeddedsvgviewer/main.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QDebug>
+
+#include "embeddedsvgviewer.h"
+
+int main(int argc, char** argv)
+{
+ QApplication app(argc, argv);
+ Q_INIT_RESOURCE(embeddedsvgviewer);
+
+ QString filePath;
+
+ if (argc == 1)
+ filePath = QLatin1String(":/files/default.svg");
+ else if (argc == 2)
+ filePath = argv[1];
+ else {
+ qDebug() << QLatin1String("Please specify an svg file!");
+ return -1;
+ }
+
+ EmbeddedSvgViewer viewer(filePath);
+
+ viewer.showFullScreen();
+
+ return app.exec();
+}
diff --git a/demos/embedded/embeddedsvgviewer/shapes.svg b/demos/embedded/embeddedsvgviewer/shapes.svg
new file mode 100644
index 0000000..c28a711
--- /dev/null
+++ b/demos/embedded/embeddedsvgviewer/shapes.svg
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="400px"
+ height="400px"
+ baseProfile="tiny"
+ id="svg8268"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ sodipodi:docname="simple2.svg"
+ sodipodi:docbase="/nfs/OpenMoko/SVGs"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <metadata
+ id="metadata8283">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8281" />
+ <sodipodi:namedview
+ inkscape:window-height="917"
+ inkscape:window-width="1324"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ inkscape:zoom="2.1452345"
+ inkscape:cx="185.25"
+ inkscape:cy="214.75"
+ inkscape:window-x="0"
+ inkscape:window-y="30"
+ inkscape:current-layer="svg8268" />
+ <g
+ stroke="DarkBlue"
+ stroke-width="10"
+ id="g8270">
+ <rect
+ fill="blue"
+ fill-opacity="0.5"
+ x="25"
+ y="25"
+ width="175"
+ height="175"
+ id="rect8272" />
+ </g>
+ <circle
+ cx="200"
+ cy="200"
+ r="75"
+ id="circle8274"
+ sodipodi:cx="200"
+ sodipodi:cy="200"
+ sodipodi:rx="75"
+ sodipodi:ry="75"
+ transform="translate(-26.104372,21.909027)"
+ style="fill:#ffff00;fill-opacity:0.5;stroke:#000000" />
+ <polygon
+ fill="green"
+ stroke="black"
+ fill-opacity="0.5"
+ stroke-width="1"
+ points="200,225 350,225 275,350"
+ id="polygon8276" />
+ <path
+ style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:0.50196081"
+ d="M 303.7037,50.705207 C 173.88522,56.588264 90.320951,92.710345 162.85059,120.82533 C 211.91719,139.84524 196.63811,214.12391 233.86243,192.59259 C 284.31755,163.4083 299.34345,193.75691 311.11111,187.30159 C 347.88407,167.12924 269.34382,134.85785 303.81608,114.5167 C 394.71183,60.881583 332.47907,46.043712 303.7037,50.705207 z "
+ id="path8289"
+ sodipodi:nodetypes="cssssc" />
+</svg>
diff --git a/demos/embedded/embeddedsvgviewer/spheres.svg b/demos/embedded/embeddedsvgviewer/spheres.svg
new file mode 100644
index 0000000..e108777
--- /dev/null
+++ b/demos/embedded/embeddedsvgviewer/spheres.svg
@@ -0,0 +1,81 @@
+<?xml version="1.0" standalone="no"?>
+<svg width="8cm" height="8cm" viewBox="0 0 400 400"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink/"
+ baseProfile="tiny" version="1.2">
+ <title>Spheres</title>
+ <desc>Gradient filled spheres with different colors.</desc>
+ <defs>
+ <!-- Create radial gradients for each circle to make them look like
+ spheres. -->
+ <radialGradient id="blueSphere" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" />
+ <stop offset="75%" stop-color="blue" />
+ <stop offset="100%" stop-color="#222244" />
+ </radialGradient>
+ <radialGradient id="redSphere" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" />
+ <stop offset="75%" stop-color="red" />
+ <stop offset="100%" stop-color="#442222" />
+ </radialGradient>
+ <radialGradient id="greenSphere" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" />
+ <stop offset="75%" stop-color="green" />
+ <stop offset="100%" stop-color="#113311" />
+ </radialGradient>
+ <radialGradient id="yellowSphere" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" />
+ <stop offset="75%" stop-color="yellow" />
+ <stop offset="100%" stop-color="#444422" />
+ </radialGradient>
+ <radialGradient id="shadowGrad" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="50">
+ <stop offset="0%" stop-color="black" stop-opacity="1.0" />
+ <stop offset="100%" stop-color="white" stop-opacity="0.0" />
+ </radialGradient>
+
+ <!-- Define a shadow for each sphere. -->
+ <circle id="shadow" fill="url(#shadowGrad)" cx="0" cy="0" r="100" />
+ </defs>
+ <g fill="#ffee99" stroke="none" >
+ <rect x="0" y="0" width="400" height="400" />
+ </g>
+ <g fill="white" stroke="none" >
+ <rect x="0" y="175" width="400" height="225" />
+ </g>
+ <g transform="translate(200,290) scale(2.0,1.0) rotate(45)" >
+ <rect fill="#a6ce39" x="-69" y="-69" width="138" height="138" />
+ <circle fill="black" cx="0" cy="0" r="50" />
+ <circle fill="#a6ce39" cx="0" cy="0" r="33" />
+ <path fill="black" d="M 37,50 L 50,37 L 12,-1 L 22,-11 L 10,-24 L -24,10
+ L -11,22 L -1,12 Z" />
+ <animateTransform attributeName="transform" type="rotate" values="0; 360"
+ begin="0s" dur="10s" fill="freeze" />
+ </g>
+ <g transform="translate(200,175)">
+ <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
+ <circle fill="url(#blueSphere)" cx="0" cy="0" r="100" />
+ </g>
+ <g transform="translate(315,240)">
+ <g transform="scale(0.5,0.5)">
+ <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
+ <circle fill="url(#redSphere)" cx="0" cy="0" r="100" />
+ </g>
+ </g>
+ <g transform="translate(80,275)">
+ <g transform="scale(0.65,0.65)">
+ <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
+ <circle fill="url(#greenSphere)" cx="0" cy="0" r="100" />
+ </g>
+ </g>
+ <g transform="translate(255,325)">
+ <g transform="scale(0.3,0.3)">
+ <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
+ <circle fill="url(#yellowSphere)" cx="0" cy="0" r="100" />
+ </g>
+ </g>
+</svg>
diff --git a/demos/embedded/fluidlauncher/config.xml b/demos/embedded/fluidlauncher/config.xml
new file mode 100644
index 0000000..6cb4be7
--- /dev/null
+++ b/demos/embedded/fluidlauncher/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<demolauncher>
+ <demos>
+ <example filename="../embeddedsvgviewer/embeddedsvgviewer" name="SVG Viewer" image="screenshots/embeddedsvgviewer.png" args="../embeddedsvgviewer/shapes.svg"/>
+ <example filename="../styledemo/styledemo" name="Stylesheets" image="screenshots/styledemo.png"/>
+ <example filename="../../deform/deform" name="Vector Deformation" image="screenshots/deform.png" args="-small-screen"/>
+ <example filename="../../pathstroke/pathstroke" name="Path Stroking" image="screenshots/pathstroke.png" args="-small-screen"/>
+ <example filename="../../../examples/widgets/wiggly/wiggly" name="Wiggly Text" image="screenshots/wiggly.png"/>
+ <example filename="../../../examples/painting/concentriccircles/concentriccircles" name="Concentric Circles" image="screenshots/concentriccircles.png"/>
+<!--
+ <example filename="../../../examples/graphicsview/elasticnodes/elasticnodes" name="Elastic Nodes" image="screenshots/elasticnodes.png" args="-maximize"/>
+ <example filename="../../../examples/assistant/simpletextviewer/simpletextviewer" name="Simple Text Viewer" image="../../../doc/html/images/simpletextviewer-mainwindow.png"/>
+ <example filename="../../../examples/dialogs/trivialwizard/trivialwizard" name="Trivial Wizard" image="../../../doc/html/images/trivialwizard-example-conclusion.png"/>
+ <example filename="../../../examples/draganddrop/draggableicons/draggableicons" name="Draggable Icons" image="../../../doc/html/images/draggableicons-example.png"/>
+ <example filename="../../../examples/draganddrop/draggabletext/draggabletext" name="Draggable Text" image="../../../doc/html/images/draggabletext-example.png"/>
+ <example filename="../../../examples/draganddrop/fridgemagnets/fridgemagnets" name="Fridge Magnets" image="../../../doc/html/images/fridgemagnets-example.png"/>
+ <example filename="../../../examples/graphicsview/collidingmice/collidingmice" name="Colliding Mice" image="../../../doc/html/images/collidingmice-example.png"/>
+ <example filename="../../../examples/graphicsview/padnavigator/padnavigator" name="Pad Navigator" image="../../../doc/html/images/padnavigator-example.png"/>
+ <example filename="../../../examples/itemviews/coloreditorfactory/coloreditorfactory" name="Color Editor" image="../../../doc/html/images/coloreditorfactoryimage.png"/>
+-->
+
+ </demos>
+ <slideshow timeout="60000" interval="10000">
+ <imagedir dir="slides"/>
+ </slideshow>
+</demolauncher>
diff --git a/demos/embedded/fluidlauncher/config_s60/config.xml b/demos/embedded/fluidlauncher/config_s60/config.xml
new file mode 100644
index 0000000..41b3b6d
--- /dev/null
+++ b/demos/embedded/fluidlauncher/config_s60/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<demolauncher>
+ <demos>
+ <example filename="embeddedsvgviewer" name="SVG Viewer" image="screenshots/embeddedsvgviewer.png" args="/data/images/qt/demos/embeddedsvgviewer/shapes.svg"/>
+ <example filename="styledemo" name="Stylesheets" image="screenshots/styledemo.png"/>
+ <example filename="deform" name="Vector Deformation" image="screenshots/deform.png" args="-small-screen"/>
+ <example filename="pathstroke" name="Path Stroking" image="screenshots/pathstroke.png" args="-small-screen"/>
+ <example filename="wiggly" name="Wiggly Text" image="screenshots/wiggly.png" args="-small-screen"/>
+ <example filename="ftp" name="Ftp Client" image="screenshots/ftp.png"/>
+ <example filename="context2d" name="Context2d" image="screenshots/context2d.png"/>
+ <example filename="saxbookmarks" name="SaxBookmarks" image="screenshots/saxbookmarks.png"/>
+ <example filename="desktopservices" name="Desktop Services" image="screenshots/desktopservices.png"/>
+ <example filename="fridgemagnets" name="Fridge Magnets" image="screenshots/fridgemagnets.png" args="-small-screen"/>
+ <example filename="drilldown" name="Drilldown" image="screenshots/drilldown.png"/>
+ </demos>
+ <slideshow timeout="60000" interval="10000">
+ <imagedir dir="slides"/>
+ </slideshow>
+</demolauncher>
diff --git a/demos/embedded/fluidlauncher/config_wince/config.xml b/demos/embedded/fluidlauncher/config_wince/config.xml
new file mode 100644
index 0000000..3b57770
--- /dev/null
+++ b/demos/embedded/fluidlauncher/config_wince/config.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<demolauncher>
+ <demos>
+ <example filename="embeddedsvgviewer" name="SVG Viewer" image="screenshots/embeddedsvgviewer.png" args="shapes.svg"/>
+ <example filename="styledemo" name="Stylesheets" image="screenshots/styledemo.png"/>
+ <example filename="deform" name="Vector Deformation" image="screenshots/deform.png" args="-small-screen"/>
+ <example filename="pathstroke" name="Path Stroking" image="screenshots/pathstroke.png" args="-small-screen"/>
+ <example filename="wiggly" name="Wiggly Text" image="screenshots/wiggly.png"/>
+ </demos>
+ <slideshow timeout="60000" interval="10000">
+ <imagedir dir="slides"/>
+ </slideshow>
+</demolauncher>
diff --git a/demos/embedded/fluidlauncher/demoapplication.cpp b/demos/embedded/fluidlauncher/demoapplication.cpp
new file mode 100644
index 0000000..c5abfb9
--- /dev/null
+++ b/demos/embedded/fluidlauncher/demoapplication.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+#include <QDir>
+
+#include "demoapplication.h"
+
+
+
+DemoApplication::DemoApplication(QString executableName, QString caption, QString imageName, QStringList args)
+{
+ imagePath = imageName;
+ appCaption = caption;
+
+ if (executableName[0] == QLatin1Char('/'))
+ executablePath = executableName;
+ else
+ executablePath = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + executableName);
+
+ arguments = args;
+
+ process.setProcessChannelMode(QProcess::ForwardedChannels);
+
+ QObject::connect( &process, SIGNAL(finished(int, QProcess::ExitStatus)),
+ this, SLOT(processFinished(int, QProcess::ExitStatus)));
+
+ QObject::connect( &process, SIGNAL(error(QProcess::ProcessError)),
+ this, SLOT(processError(QProcess::ProcessError)));
+
+ QObject::connect( &process, SIGNAL(started()), this, SLOT(processStarted()));
+}
+
+
+void DemoApplication::launch()
+{
+ process.start(executablePath, arguments);
+}
+
+QImage* DemoApplication::getImage()
+{
+ return new QImage(imagePath);
+}
+
+QString DemoApplication::getCaption()
+{
+ return appCaption;
+}
+
+void DemoApplication::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ Q_UNUSED(exitCode);
+ Q_UNUSED(exitStatus);
+
+ emit demoFinished();
+
+ QObject::disconnect(this, SIGNAL(demoStarted()), 0, 0);
+ QObject::disconnect(this, SIGNAL(demoFinished()), 0, 0);
+}
+
+void DemoApplication::processError(QProcess::ProcessError err)
+{
+ qDebug() << "Process error: " << err;
+ if (err == QProcess::Crashed)
+ emit demoFinished();
+}
+
+
+void DemoApplication::processStarted()
+{
+ emit demoStarted();
+}
+
+
+
+
+
+
diff --git a/demos/embedded/fluidlauncher/demoapplication.h b/demos/embedded/fluidlauncher/demoapplication.h
new file mode 100644
index 0000000..84ce1d4
--- /dev/null
+++ b/demos/embedded/fluidlauncher/demoapplication.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEMO_APPLICATION_H
+#define DEMO_APPLICATION_H
+
+#include <QPixmap>
+#include <QImage>
+#include <QProcess>
+#include <QObject>
+
+class DemoApplication : public QObject
+{
+ Q_OBJECT
+
+public:
+ DemoApplication(QString executableName, QString caption, QString imageName, QStringList args);
+ void launch();
+ QImage* getImage();
+ QString getCaption();
+
+public slots:
+ void processStarted();
+ void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
+ void processError(QProcess::ProcessError err);
+
+signals:
+ void demoStarted();
+ void demoFinished();
+
+private:
+ QString imagePath;
+ QString appCaption;
+ QString executablePath;
+ QStringList arguments;
+ QProcess process;
+};
+
+
+
+
+#endif
+
+
diff --git a/demos/embedded/fluidlauncher/fluidlauncher.cpp b/demos/embedded/fluidlauncher/fluidlauncher.cpp
new file mode 100644
index 0000000..9a4f2ca
--- /dev/null
+++ b/demos/embedded/fluidlauncher/fluidlauncher.cpp
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QXmlStreamReader>
+
+#include "fluidlauncher.h"
+
+
+#define DEFAULT_INPUT_TIMEOUT 10000
+#define SIZING_FACTOR_HEIGHT 6/10
+#define SIZING_FACTOR_WIDTH 6/10
+
+FluidLauncher::FluidLauncher(QStringList* args)
+{
+ pictureFlowWidget = new PictureFlow();
+ slideShowWidget = new SlideShow();
+ inputTimer = new QTimer();
+
+ QRect screen_size = QApplication::desktop()->screenGeometry();
+
+ QObject::connect(pictureFlowWidget, SIGNAL(itemActivated(int)), this, SLOT(launchApplication(int)));
+ QObject::connect(pictureFlowWidget, SIGNAL(inputReceived()), this, SLOT(resetInputTimeout()));
+ QObject::connect(slideShowWidget, SIGNAL(inputReceived()), this, SLOT(switchToLauncher()));
+ QObject::connect(inputTimer, SIGNAL(timeout()), this, SLOT(inputTimedout()));
+
+ inputTimer->setSingleShot(true);
+ inputTimer->setInterval(DEFAULT_INPUT_TIMEOUT);
+
+ const int h = screen_size.height() * SIZING_FACTOR_HEIGHT;
+ const int w = screen_size.width() * SIZING_FACTOR_WIDTH;
+ const int hh = qMin(h, w);
+ const int ww = hh / 3 * 2;
+ pictureFlowWidget->setSlideSize(QSize(ww, hh));
+
+ bool success;
+ int configIndex = args->indexOf("-config");
+ if ( (configIndex != -1) && (configIndex != args->count()-1) )
+ success = loadConfig(args->at(configIndex+1));
+ else
+ success = loadConfig("config.xml");
+
+ if (success) {
+ populatePictureFlow();
+
+ pictureFlowWidget->showFullScreen();
+ inputTimer->start();
+ } else {
+ pictureFlowWidget->setAttribute(Qt::WA_DeleteOnClose, true);
+ pictureFlowWidget->close();
+ }
+
+}
+
+FluidLauncher::~FluidLauncher()
+{
+ delete pictureFlowWidget;
+ delete slideShowWidget;
+}
+
+bool FluidLauncher::loadConfig(QString configPath)
+{
+ QFile xmlFile(configPath);
+
+ if (!xmlFile.exists() || (xmlFile.error() != QFile::NoError)) {
+ qDebug() << "ERROR: Unable to open config file " << configPath;
+ return false;
+ }
+
+ slideShowWidget->clearImages();
+
+ xmlFile.open(QIODevice::ReadOnly);
+ QXmlStreamReader reader(&xmlFile);
+ while (!reader.atEnd()) {
+ reader.readNext();
+
+ if (reader.isStartElement()) {
+ if (reader.name() == "demos")
+ parseDemos(reader);
+ else if(reader.name() == "slideshow")
+ parseSlideshow(reader);
+ }
+ }
+
+ if (reader.hasError()) {
+ qDebug() << QString("Error parsing %1 on line %2 column %3: \n%4")
+ .arg(configPath)
+ .arg(reader.lineNumber())
+ .arg(reader.columnNumber())
+ .arg(reader.errorString());
+ }
+
+ // Append an exit Item
+ DemoApplication* exitItem = new DemoApplication(QString(), QLatin1String("Exit Embedded Demo"), QString(), QStringList());
+ demoList.append(exitItem);
+
+ return true;
+}
+
+
+void FluidLauncher::parseDemos(QXmlStreamReader& reader)
+{
+ while (!reader.atEnd()) {
+ reader.readNext();
+ if (reader.isStartElement() && reader.name() == "example") {
+ QXmlStreamAttributes attrs = reader.attributes();
+ QStringRef filename = attrs.value("filename");
+ if (!filename.isEmpty()) {
+ QStringRef name = attrs.value("name");
+ QStringRef image = attrs.value("image");
+ QStringRef args = attrs.value("args");
+
+ DemoApplication* newDemo = new DemoApplication(
+ filename.toString(),
+ name.isEmpty() ? "Unamed Demo" : name.toString(),
+ image.toString(),
+ args.toString().split(" "));
+ demoList.append(newDemo);
+ }
+ } else if(reader.isEndElement() && reader.name() == "demos") {
+ return;
+ }
+ }
+}
+
+void FluidLauncher::parseSlideshow(QXmlStreamReader& reader)
+{
+ QXmlStreamAttributes attrs = reader.attributes();
+
+ QStringRef timeout = attrs.value("timeout");
+ bool valid;
+ if (!timeout.isEmpty()) {
+ int t = timeout.toString().toInt(&valid);
+ if (valid)
+ inputTimer->setInterval(t);
+ }
+
+ QStringRef interval = attrs.value("interval");
+ if (!interval.isEmpty()) {
+ int i = interval.toString().toInt(&valid);
+ if (valid)
+ slideShowWidget->setSlideInterval(i);
+ }
+
+ while (!reader.atEnd()) {
+ reader.readNext();
+ if (reader.isStartElement()) {
+ QXmlStreamAttributes attrs = reader.attributes();
+ if (reader.name() == "imagedir") {
+ QStringRef dir = attrs.value("dir");
+ slideShowWidget->addImageDir(dir.toString());
+ } else if(reader.name() == "image") {
+ QStringRef image = attrs.value("image");
+ slideShowWidget->addImage(image.toString());
+ }
+ } else if(reader.isEndElement() && reader.name() == "slideshow") {
+ return;
+ }
+ }
+
+}
+
+void FluidLauncher::populatePictureFlow()
+{
+ pictureFlowWidget->setSlideCount(demoList.count());
+
+ for (int i=demoList.count()-1; i>=0; --i) {
+ pictureFlowWidget->setSlide(i, *(demoList[i]->getImage()));
+ pictureFlowWidget->setSlideCaption(i, demoList[i]->getCaption());
+ }
+
+ pictureFlowWidget->setCurrentSlide(demoList.count()/2);
+}
+
+
+void FluidLauncher::launchApplication(int index)
+{
+ // NOTE: Clearing the caches will free up more memory for the demo but will cause
+ // a delay upon returning, as items are reloaded.
+ //pictureFlowWidget->clearCaches();
+
+ if (index == demoList.size() -1) {
+ qApp->quit();
+ return;
+ }
+
+ inputTimer->stop();
+ pictureFlowWidget->hide();
+
+ QObject::connect(demoList[index], SIGNAL(demoFinished()), this, SLOT(demoFinished()));
+
+ demoList[index]->launch();
+}
+
+
+void FluidLauncher::switchToLauncher()
+{
+ slideShowWidget->stopShow();
+ inputTimer->start();
+}
+
+
+void FluidLauncher::resetInputTimeout()
+{
+ if (inputTimer->isActive())
+ inputTimer->start();
+}
+
+void FluidLauncher::inputTimedout()
+{
+ switchToSlideshow();
+}
+
+
+void FluidLauncher::switchToSlideshow()
+{
+ inputTimer->stop();
+ slideShowWidget->startShow();
+}
+
+void FluidLauncher::demoFinished()
+{
+ pictureFlowWidget->showFullScreen();
+ inputTimer->start();
+}
+
diff --git a/demos/embedded/fluidlauncher/fluidlauncher.h b/demos/embedded/fluidlauncher/fluidlauncher.h
new file mode 100644
index 0000000..d064edd
--- /dev/null
+++ b/demos/embedded/fluidlauncher/fluidlauncher.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FLUID_LAUNCHER_H
+#define FLUID_LAUNCHER_H
+
+#include <QtGui>
+#include <QTimer>
+#include <QStringRef>
+
+#include "pictureflow.h"
+#include "slideshow.h"
+#include "demoapplication.h"
+
+class FluidLauncher : public QObject
+{
+ Q_OBJECT
+
+public:
+ FluidLauncher(QStringList* args);
+ ~FluidLauncher();
+
+public slots:
+ void launchApplication(int index);
+ void switchToLauncher();
+ void resetInputTimeout();
+ void inputTimedout();
+ void demoFinished();
+
+private:
+ PictureFlow* pictureFlowWidget;
+ SlideShow* slideShowWidget;
+ QTimer* inputTimer;
+ QList<DemoApplication*> demoList;
+
+ bool loadConfig(QString configPath);
+ void populatePictureFlow();
+ void switchToSlideshow();
+ void parseDemos(QXmlStreamReader& reader);
+ void parseSlideshow(QXmlStreamReader& reader);
+
+};
+
+
+#endif
diff --git a/demos/embedded/fluidlauncher/fluidlauncher.pro b/demos/embedded/fluidlauncher/fluidlauncher.pro
new file mode 100644
index 0000000..ed2530c
--- /dev/null
+++ b/demos/embedded/fluidlauncher/fluidlauncher.pro
@@ -0,0 +1,138 @@
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+
+# Input
+HEADERS += \
+ demoapplication.h \
+ fluidlauncher.h \
+ pictureflow.h \
+ slideshow.h
+
+SOURCES += \
+ demoapplication.cpp \
+ fluidlauncher.cpp \
+ main.cpp \
+ pictureflow.cpp \
+ slideshow.cpp
+
+embedded{
+ target.path = $$[QT_INSTALL_DEMOS]/embedded/fluidlauncher
+ sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.html config.xml screenshots slides
+ sources.path = $$[QT_INSTALL_DEMOS]/embedded/fluidlauncher
+ INSTALLS += target sources
+}
+
+wince*{
+ QT += svg
+
+ BUILD_DIR = release
+ if(!debug_and_release|build_pass):CONFIG(debug, debug|release) {
+ BUILD_DIR = debug
+ }
+
+ executables.sources = \
+ $$QT_BUILD_TREE/demos/embedded/embeddedsvgviewer/$${BUILD_DIR}/embeddedsvgviewer.exe \
+ $$QT_BUILD_TREE/demos/embedded/styledemo/$${BUILD_DIR}/styledemo.exe \
+ $$QT_BUILD_TREE/demos/deform/$${BUILD_DIR}/deform.exe \
+ $$QT_BUILD_TREE/demos/pathstroke/$${BUILD_DIR}/pathstroke.exe \
+ $$QT_BUILD_TREE/examples/graphicsview/elasticnodes/$${BUILD_DIR}/elasticnodes.exe \
+ $$QT_BUILD_TREE/examples/widgets/wiggly/$${BUILD_DIR}/wiggly.exe \
+ $$QT_BUILD_TREE/examples/painting/concentriccircles/$${BUILD_DIR}/concentriccircles.exe \
+ $$QT_BUILD_TREE/examples/draganddrop/$${BUILD_DIR}/fridgemagnets.exe
+
+ executables.path = .
+
+ files.sources = $$PWD/screenshots $$PWD/slides $$PWD/../embeddedsvgviewer/shapes.svg
+ files.path = .
+
+ config.sources = $$PWD/config_wince/config.xml
+ config.path = .
+
+ DEPLOYMENT += config files executables
+
+ DEPLOYMENT_PLUGIN += qgif qjpeg qmng qsvg
+}
+
+symbian {
+ load(data_caging_paths)
+
+ TARGET.UID3 = 0xA000A641
+
+ executables.sources = \
+ embeddedsvgviewer.exe \
+ styledemo.exe \
+ deform.exe \
+ pathstroke.exe \
+ wiggly.exe \
+ ftp.exe \
+ context2d.exe \
+ saxbookmarks.exe \
+ desktopservices.exe \
+ fridgemagnets.exe \
+ drilldown.exe
+
+ executables.path = /sys/bin
+
+ reg_resource.sources = \
+ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/embeddedsvgviewer_reg.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/styledemo_reg.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/deform_reg.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/pathstroke_reg.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/wiggly_reg.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/ftp_reg.rsc\
+ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/context2d_reg.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/saxbookmarks_reg.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/desktopservices_reg.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/fridgemagnets_reg.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/drilldown_reg.rsc
+
+ reg_resource.path = $$REG_RESOURCE_IMPORT_DIR
+
+
+ resource.sources = \
+ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/embeddedsvgviewer.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/styledemo.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/deform.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/pathstroke.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/wiggly.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/ftp.rsc\
+ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/context2d.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/saxbookmarks.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/desktopservices.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/fridgemagnets.rsc \
+ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/drilldown.rsc
+
+ resource.path = $$APP_RESOURCE_DIR
+
+ mifs.sources = \
+ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/0xA000C611.mif
+ mifs.path = $$APP_RESOURCE_DIR
+
+ files.sources = $$PWD/screenshots $$PWD/slides
+ files.path = .
+
+ config.sources = $$PWD/config_s60/config.xml
+ config.path = .
+
+ viewerimages.sources = $$PWD/../embeddedsvgviewer/shapes.svg
+ viewerimages.path = /data/images/qt/demos/embeddedsvgviewer
+
+ desktopservices_music.sources = \
+ $$PWD/../desktopservices/data/*.mp3 \
+ $$PWD/../desktopservices/data/*.wav
+ desktopservices_music.path = /data/sounds
+
+ desktopservices_images.sources = $$PWD/../desktopservices/data/*.png
+ desktopservices_images.path = /data/images
+
+ saxbookmarks.sources = $$PWD/../../../examples/xml/saxbookmarks/frankf.xbel
+ saxbookmarks.sources += $$PWD/../../../examples/xml/saxbookmarks/jenniferf.xbel
+ saxbookmarks.path = /data/qt/saxbookmarks
+
+ DEPLOYMENT += config files executables viewerimages saxbookmarks reg_resource resource \
+ mifs desktopservices_music desktopservices_images
+
+ TARGET.EPOCHEAPSIZE = 100000 20000000
+}
diff --git a/demos/embedded/fluidlauncher/main.cpp b/demos/embedded/fluidlauncher/main.cpp
new file mode 100644
index 0000000..05e820e
--- /dev/null
+++ b/demos/embedded/fluidlauncher/main.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QStringList>
+
+#include "fluidlauncher.h"
+
+
+int main(int argc, char** argv)
+{
+ QStringList originalArgs;
+
+ for (int i=0; i<argc; i++)
+ originalArgs << argv[i];
+
+ QApplication app(argc, argv);
+ FluidLauncher launcher(&originalArgs);
+
+
+ return app.exec();
+}
diff --git a/demos/embedded/fluidlauncher/pictureflow.cpp b/demos/embedded/fluidlauncher/pictureflow.cpp
new file mode 100644
index 0000000..e2f8284
--- /dev/null
+++ b/demos/embedded/fluidlauncher/pictureflow.cpp
@@ -0,0 +1,1434 @@
+/****************************************************************************
+**
+* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+* This is version of the Pictureflow animated image show widget modified by Nokia.
+*
+* $QT_BEGIN_LICENSE:LGPL$
+* No Commercial Usage
+* This file contains pre-release code and may not be distributed.
+* You may use this file in accordance with the terms and conditions
+* contained in the either Technology Preview License Agreement or the
+* Beta Release License Agreement.
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this file may be used under the terms of the GNU Lesser
+* General Public License version 2.1 as published by the Free Software
+* Foundation and appearing in the file LICENSE.LGPL included in the
+* packaging of this file. Please review the following information to
+* ensure the GNU Lesser General Public License version 2.1 requirements
+* will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+*
+* In addition, as a special exception, Nokia gives you certain
+* additional rights. These rights are described in the Nokia Qt LGPL
+* Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+* package.
+*
+* GNU General Public License Usage
+* Alternatively, this file may be used under the terms of the GNU
+* General Public License version 3.0 as published by the Free Software
+* Foundation and appearing in the file LICENSE.GPL included in the
+* packaging of this file. Please review the following information to
+* ensure the GNU General Public License version 3.0 requirements will be
+* met: http://www.gnu.org/copyleft/gpl.html.
+*
+* If you are unsure which license is appropriate for your use, please
+* contact the sales department at qt-sales@nokia.com.
+* $QT_END_LICENSE$
+*
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of the <organization> nor the
+* names of its contributors may be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY TROLLTECH ASA ``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 <copyright holder> 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.
+
+****************************************************************************/
+
+/*
+ ORIGINAL COPYRIGHT HEADER
+ PictureFlow - animated image show widget
+ http://pictureflow.googlecode.com
+
+ Copyright (C) 2007 Ariya Hidayat (ariya@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 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 "pictureflow.h"
+
+#include <QBasicTimer>
+#include <QCache>
+#include <QImage>
+#include <QKeyEvent>
+#include <QPainter>
+#include <QPixmap>
+#include <QTimer>
+#include <QVector>
+#include <QWidget>
+#include <QTime>
+
+#ifdef Q_WS_QWS
+#include <QScreen>
+#endif
+
+#include <QDebug>
+
+static const int captionFontSize =
+#ifdef Q_WS_S60
+ 8;
+#else
+ 14;
+#endif
+
+
+// uncomment this to enable bilinear filtering for texture mapping
+// gives much better rendering, at the cost of memory space
+// #define PICTUREFLOW_BILINEAR_FILTER
+
+// for fixed-point arithmetic, we need minimum 32-bit long
+// long long (64-bit) might be useful for multiplication and division
+typedef long PFreal;
+
+typedef unsigned short QRgb565;
+
+#define RGB565_RED_MASK 0xF800
+#define RGB565_GREEN_MASK 0x07E0
+#define RGB565_BLUE_MASK 0x001F
+
+#define RGB565_RED(col) ((col&RGB565_RED_MASK)>>11)
+#define RGB565_GREEN(col) ((col&RGB565_GREEN_MASK)>>5)
+#define RGB565_BLUE(col) (col&RGB565_BLUE_MASK)
+
+#define PFREAL_SHIFT 10
+#define PFREAL_FACTOR (1 << PFREAL_SHIFT)
+#define PFREAL_ONE (1 << PFREAL_SHIFT)
+#define PFREAL_HALF (PFREAL_ONE >> 1)
+
+inline PFreal fmul(PFreal a, PFreal b)
+{
+ return ((long long)(a))*((long long)(b)) >> PFREAL_SHIFT;
+}
+
+inline PFreal fdiv(PFreal num, PFreal den)
+{
+ long long p = (long long)(num) << (PFREAL_SHIFT*2);
+ long long q = p / (long long)den;
+ long long r = q >> PFREAL_SHIFT;
+
+ return r;
+}
+
+inline float fixedToFloat(PFreal val)
+{
+ return ((float)val) / (float)PFREAL_ONE;
+}
+
+inline PFreal floatToFixed(float val)
+{
+ return (PFreal)(val*PFREAL_ONE);
+}
+
+#define IANGLE_MAX 1024
+#define IANGLE_MASK 1023
+
+// warning: regenerate the table if IANGLE_MAX and PFREAL_SHIFT are changed!
+static const PFreal sinTable[IANGLE_MAX] = {
+ 3, 9, 15, 21, 28, 34, 40, 47,
+ 53, 59, 65, 72, 78, 84, 90, 97,
+ 103, 109, 115, 122, 128, 134, 140, 147,
+ 153, 159, 165, 171, 178, 184, 190, 196,
+ 202, 209, 215, 221, 227, 233, 239, 245,
+ 251, 257, 264, 270, 276, 282, 288, 294,
+ 300, 306, 312, 318, 324, 330, 336, 342,
+ 347, 353, 359, 365, 371, 377, 383, 388,
+ 394, 400, 406, 412, 417, 423, 429, 434,
+ 440, 446, 451, 457, 463, 468, 474, 479,
+ 485, 491, 496, 501, 507, 512, 518, 523,
+ 529, 534, 539, 545, 550, 555, 561, 566,
+ 571, 576, 581, 587, 592, 597, 602, 607,
+ 612, 617, 622, 627, 632, 637, 642, 647,
+ 652, 656, 661, 666, 671, 675, 680, 685,
+ 690, 694, 699, 703, 708, 712, 717, 721,
+ 726, 730, 735, 739, 743, 748, 752, 756,
+ 760, 765, 769, 773, 777, 781, 785, 789,
+ 793, 797, 801, 805, 809, 813, 816, 820,
+ 824, 828, 831, 835, 839, 842, 846, 849,
+ 853, 856, 860, 863, 866, 870, 873, 876,
+ 879, 883, 886, 889, 892, 895, 898, 901,
+ 904, 907, 910, 913, 916, 918, 921, 924,
+ 927, 929, 932, 934, 937, 939, 942, 944,
+ 947, 949, 951, 954, 956, 958, 960, 963,
+ 965, 967, 969, 971, 973, 975, 977, 978,
+ 980, 982, 984, 986, 987, 989, 990, 992,
+ 994, 995, 997, 998, 999, 1001, 1002, 1003,
+ 1004, 1006, 1007, 1008, 1009, 1010, 1011, 1012,
+ 1013, 1014, 1015, 1015, 1016, 1017, 1018, 1018,
+ 1019, 1019, 1020, 1020, 1021, 1021, 1022, 1022,
+ 1022, 1023, 1023, 1023, 1023, 1023, 1023, 1023,
+ 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1022,
+ 1022, 1022, 1021, 1021, 1020, 1020, 1019, 1019,
+ 1018, 1018, 1017, 1016, 1015, 1015, 1014, 1013,
+ 1012, 1011, 1010, 1009, 1008, 1007, 1006, 1004,
+ 1003, 1002, 1001, 999, 998, 997, 995, 994,
+ 992, 990, 989, 987, 986, 984, 982, 980,
+ 978, 977, 975, 973, 971, 969, 967, 965,
+ 963, 960, 958, 956, 954, 951, 949, 947,
+ 944, 942, 939, 937, 934, 932, 929, 927,
+ 924, 921, 918, 916, 913, 910, 907, 904,
+ 901, 898, 895, 892, 889, 886, 883, 879,
+ 876, 873, 870, 866, 863, 860, 856, 853,
+ 849, 846, 842, 839, 835, 831, 828, 824,
+ 820, 816, 813, 809, 805, 801, 797, 793,
+ 789, 785, 781, 777, 773, 769, 765, 760,
+ 756, 752, 748, 743, 739, 735, 730, 726,
+ 721, 717, 712, 708, 703, 699, 694, 690,
+ 685, 680, 675, 671, 666, 661, 656, 652,
+ 647, 642, 637, 632, 627, 622, 617, 612,
+ 607, 602, 597, 592, 587, 581, 576, 571,
+ 566, 561, 555, 550, 545, 539, 534, 529,
+ 523, 518, 512, 507, 501, 496, 491, 485,
+ 479, 474, 468, 463, 457, 451, 446, 440,
+ 434, 429, 423, 417, 412, 406, 400, 394,
+ 388, 383, 377, 371, 365, 359, 353, 347,
+ 342, 336, 330, 324, 318, 312, 306, 300,
+ 294, 288, 282, 276, 270, 264, 257, 251,
+ 245, 239, 233, 227, 221, 215, 209, 202,
+ 196, 190, 184, 178, 171, 165, 159, 153,
+ 147, 140, 134, 128, 122, 115, 109, 103,
+ 97, 90, 84, 78, 72, 65, 59, 53,
+ 47, 40, 34, 28, 21, 15, 9, 3,
+ -4, -10, -16, -22, -29, -35, -41, -48,
+ -54, -60, -66, -73, -79, -85, -91, -98,
+ -104, -110, -116, -123, -129, -135, -141, -148,
+ -154, -160, -166, -172, -179, -185, -191, -197,
+ -203, -210, -216, -222, -228, -234, -240, -246,
+ -252, -258, -265, -271, -277, -283, -289, -295,
+ -301, -307, -313, -319, -325, -331, -337, -343,
+ -348, -354, -360, -366, -372, -378, -384, -389,
+ -395, -401, -407, -413, -418, -424, -430, -435,
+ -441, -447, -452, -458, -464, -469, -475, -480,
+ -486, -492, -497, -502, -508, -513, -519, -524,
+ -530, -535, -540, -546, -551, -556, -562, -567,
+ -572, -577, -582, -588, -593, -598, -603, -608,
+ -613, -618, -623, -628, -633, -638, -643, -648,
+ -653, -657, -662, -667, -672, -676, -681, -686,
+ -691, -695, -700, -704, -709, -713, -718, -722,
+ -727, -731, -736, -740, -744, -749, -753, -757,
+ -761, -766, -770, -774, -778, -782, -786, -790,
+ -794, -798, -802, -806, -810, -814, -817, -821,
+ -825, -829, -832, -836, -840, -843, -847, -850,
+ -854, -857, -861, -864, -867, -871, -874, -877,
+ -880, -884, -887, -890, -893, -896, -899, -902,
+ -905, -908, -911, -914, -917, -919, -922, -925,
+ -928, -930, -933, -935, -938, -940, -943, -945,
+ -948, -950, -952, -955, -957, -959, -961, -964,
+ -966, -968, -970, -972, -974, -976, -978, -979,
+ -981, -983, -985, -987, -988, -990, -991, -993,
+ -995, -996, -998, -999, -1000, -1002, -1003, -1004,
+ -1005, -1007, -1008, -1009, -1010, -1011, -1012, -1013,
+ -1014, -1015, -1016, -1016, -1017, -1018, -1019, -1019,
+ -1020, -1020, -1021, -1021, -1022, -1022, -1023, -1023,
+ -1023, -1024, -1024, -1024, -1024, -1024, -1024, -1024,
+ -1024, -1024, -1024, -1024, -1024, -1024, -1024, -1023,
+ -1023, -1023, -1022, -1022, -1021, -1021, -1020, -1020,
+ -1019, -1019, -1018, -1017, -1016, -1016, -1015, -1014,
+ -1013, -1012, -1011, -1010, -1009, -1008, -1007, -1005,
+ -1004, -1003, -1002, -1000, -999, -998, -996, -995,
+ -993, -991, -990, -988, -987, -985, -983, -981,
+ -979, -978, -976, -974, -972, -970, -968, -966,
+ -964, -961, -959, -957, -955, -952, -950, -948,
+ -945, -943, -940, -938, -935, -933, -930, -928,
+ -925, -922, -919, -917, -914, -911, -908, -905,
+ -902, -899, -896, -893, -890, -887, -884, -880,
+ -877, -874, -871, -867, -864, -861, -857, -854,
+ -850, -847, -843, -840, -836, -832, -829, -825,
+ -821, -817, -814, -810, -806, -802, -798, -794,
+ -790, -786, -782, -778, -774, -770, -766, -761,
+ -757, -753, -749, -744, -740, -736, -731, -727,
+ -722, -718, -713, -709, -704, -700, -695, -691,
+ -686, -681, -676, -672, -667, -662, -657, -653,
+ -648, -643, -638, -633, -628, -623, -618, -613,
+ -608, -603, -598, -593, -588, -582, -577, -572,
+ -567, -562, -556, -551, -546, -540, -535, -530,
+ -524, -519, -513, -508, -502, -497, -492, -486,
+ -480, -475, -469, -464, -458, -452, -447, -441,
+ -435, -430, -424, -418, -413, -407, -401, -395,
+ -389, -384, -378, -372, -366, -360, -354, -348,
+ -343, -337, -331, -325, -319, -313, -307, -301,
+ -295, -289, -283, -277, -271, -265, -258, -252,
+ -246, -240, -234, -228, -222, -216, -210, -203,
+ -197, -191, -185, -179, -172, -166, -160, -154,
+ -148, -141, -135, -129, -123, -116, -110, -104,
+ -98, -91, -85, -79, -73, -66, -60, -54,
+ -48, -41, -35, -29, -22, -16, -10, -4
+};
+
+// this is the program the generate the above table
+#if 0
+#include <stdio.h>
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#define PFREAL_ONE 1024
+#define IANGLE_MAX 1024
+
+int main(int, char**)
+{
+ FILE*f = fopen("table.c","wt");
+ fprintf(f,"PFreal sinTable[] = {\n");
+ for(int i = 0; i < 128; i++)
+ {
+ for(int j = 0; j < 8; j++)
+ {
+ int iang = j+i*8;
+ double ii = (double)iang + 0.5;
+ double angle = ii * 2 * M_PI / IANGLE_MAX;
+ double sinAngle = sin(angle);
+ fprintf(f,"%6d, ", (int)(floor(PFREAL_ONE*sinAngle)));
+ }
+ fprintf(f,"\n");
+ }
+ fprintf(f,"};\n");
+ fclose(f);
+
+ return 0;
+}
+#endif
+
+inline PFreal fsin(int iangle)
+{
+ while(iangle < 0)
+ iangle += IANGLE_MAX;
+ return sinTable[iangle & IANGLE_MASK];
+}
+
+inline PFreal fcos(int iangle)
+{
+ // quarter phase shift
+ return fsin(iangle + (IANGLE_MAX >> 2));
+}
+
+struct SlideInfo
+{
+ int slideIndex;
+ int angle;
+ PFreal cx;
+ PFreal cy;
+};
+
+class PictureFlowPrivate
+{
+public:
+ PictureFlowPrivate(PictureFlow* widget);
+
+ int slideCount() const;
+ void setSlideCount(int count);
+
+ QSize slideSize() const;
+ void setSlideSize(QSize size);
+
+ int zoomFactor() const;
+ void setZoomFactor(int z);
+
+ QImage slide(int index) const;
+ void setSlide(int index, const QImage& image);
+
+ int currentSlide() const;
+ void setCurrentSlide(int index);
+
+ int getTarget() const;
+
+ void showPrevious();
+ void showNext();
+ void showSlide(int index);
+
+ void resize(int w, int h);
+
+ void render();
+ void startAnimation();
+ void updateAnimation();
+
+ void clearSurfaceCache();
+
+ QImage buffer;
+ QBasicTimer animateTimer;
+
+ bool singlePress;
+ int singlePressThreshold;
+ QPoint firstPress;
+ QPoint previousPos;
+ QTime previousPosTimestamp;
+ int pixelDistanceMoved;
+ int pixelsToMovePerSlide;
+
+ QVector<QString> captions;
+
+private:
+ PictureFlow* widget;
+
+ int slideWidth;
+ int slideHeight;
+ int zoom;
+
+ QVector<QImage> slideImages;
+ int centerIndex;
+ SlideInfo centerSlide;
+ QVector<SlideInfo> leftSlides;
+ QVector<SlideInfo> rightSlides;
+
+ QVector<PFreal> rays;
+ int itilt;
+ int spacing;
+ PFreal offsetX;
+ PFreal offsetY;
+
+ QImage blankSurface;
+ QCache<int, QImage> surfaceCache;
+ QTimer triggerTimer;
+
+ int slideFrame;
+ int step;
+ int target;
+ int fade;
+
+ void recalc(int w, int h);
+ QRect renderSlide(const SlideInfo &slide, int alpha=256, int col1=-1, int col=-1);
+ QImage* surface(int slideIndex);
+ void triggerRender();
+ void resetSlides();
+};
+
+PictureFlowPrivate::PictureFlowPrivate(PictureFlow* w)
+{
+ widget = w;
+
+ slideWidth = 200;
+ slideHeight = 200;
+ zoom = 100;
+
+ centerIndex = 0;
+
+ slideFrame = 0;
+ step = 0;
+ target = 0;
+ fade = 256;
+
+ triggerTimer.setSingleShot(true);
+ triggerTimer.setInterval(0);
+ QObject::connect(&triggerTimer, SIGNAL(timeout()), widget, SLOT(render()));
+
+ recalc(200, 200);
+ resetSlides();
+}
+
+int PictureFlowPrivate::slideCount() const
+{
+ return slideImages.count();
+}
+
+void PictureFlowPrivate::setSlideCount(int count)
+{
+ slideImages.resize(count);
+ captions.resize(count);
+ surfaceCache.clear();
+ resetSlides();
+ triggerRender();
+}
+
+QSize PictureFlowPrivate::slideSize() const
+{
+ return QSize(slideWidth, slideHeight);
+}
+
+void PictureFlowPrivate::setSlideSize(QSize size)
+{
+ slideWidth = size.width();
+ slideHeight = size.height();
+ recalc(buffer.width(), buffer.height());
+ triggerRender();
+}
+
+int PictureFlowPrivate::zoomFactor() const
+{
+ return zoom;
+}
+
+void PictureFlowPrivate::setZoomFactor(int z)
+{
+ if(z <= 0)
+ return;
+
+ zoom = z;
+ recalc(buffer.width(), buffer.height());
+ triggerRender();
+}
+
+QImage PictureFlowPrivate::slide(int index) const
+{
+ return slideImages[index];
+}
+
+void PictureFlowPrivate::setSlide(int index, const QImage& image)
+{
+ if((index >= 0) && (index < slideImages.count()))
+ {
+ slideImages[index] = image;
+ surfaceCache.remove(index);
+ triggerRender();
+ }
+}
+
+int PictureFlowPrivate::getTarget() const
+{
+ return target;
+}
+
+int PictureFlowPrivate::currentSlide() const
+{
+ return centerIndex;
+}
+
+void PictureFlowPrivate::setCurrentSlide(int index)
+{
+ step = 0;
+ centerIndex = qBound(index, 0, slideImages.count()-1);
+ target = centerIndex;
+ slideFrame = index << 16;
+ resetSlides();
+ triggerRender();
+}
+
+void PictureFlowPrivate::showPrevious()
+{
+ if(step >= 0)
+ {
+ if(centerIndex > 0)
+ {
+ target--;
+ startAnimation();
+ }
+ }
+ else
+ {
+ target = qMax(0, centerIndex - 2);
+ }
+}
+
+void PictureFlowPrivate::showNext()
+{
+ if(step <= 0)
+ {
+ if(centerIndex < slideImages.count()-1)
+ {
+ target++;
+ startAnimation();
+ }
+ }
+ else
+ {
+ target = qMin(centerIndex + 2, slideImages.count()-1);
+ }
+}
+
+void PictureFlowPrivate::showSlide(int index)
+{
+ index = qMax(index, 0);
+ index = qMin(slideImages.count()-1, index);
+ if(index == centerSlide.slideIndex)
+ return;
+
+ target = index;
+ startAnimation();
+}
+
+void PictureFlowPrivate::resize(int w, int h)
+{
+ recalc(w, h);
+ resetSlides();
+ triggerRender();
+}
+
+
+// adjust slides so that they are in "steady state" position
+void PictureFlowPrivate::resetSlides()
+{
+ centerSlide.angle = 0;
+ centerSlide.cx = 0;
+ centerSlide.cy = 0;
+ centerSlide.slideIndex = centerIndex;
+
+ leftSlides.clear();
+ leftSlides.resize(3);
+ for(int i = 0; i < leftSlides.count(); i++)
+ {
+ SlideInfo& si = leftSlides[i];
+ si.angle = itilt;
+ si.cx = -(offsetX + spacing*i*PFREAL_ONE);
+ si.cy = offsetY;
+ si.slideIndex = centerIndex-1-i;
+ //qDebug() << "Left[" << i << "] x=" << fixedToFloat(si.cx) << ", y=" << fixedToFloat(si.cy) ;
+ }
+
+ rightSlides.clear();
+ rightSlides.resize(3);
+ for(int i = 0; i < rightSlides.count(); i++)
+ {
+ SlideInfo& si = rightSlides[i];
+ si.angle = -itilt;
+ si.cx = offsetX + spacing*i*PFREAL_ONE;
+ si.cy = offsetY;
+ si.slideIndex = centerIndex+1+i;
+ //qDebug() << "Right[" << i << "] x=" << fixedToFloat(si.cx) << ", y=" << fixedToFloat(si.cy) ;
+ }
+}
+
+#define BILINEAR_STRETCH_HOR 4
+#define BILINEAR_STRETCH_VER 4
+
+static QImage prepareSurface(QImage img, int w, int h)
+{
+ Qt::TransformationMode mode = Qt::SmoothTransformation;
+ img = img.scaled(w, h, Qt::IgnoreAspectRatio, mode);
+
+ // slightly larger, to accomodate for the reflection
+ int hs = h * 2;
+ int hofs = h / 3;
+
+ // offscreen buffer: black is sweet
+ QImage result(hs, w, QImage::Format_RGB16);
+ result.fill(0);
+
+ // transpose the image, this is to speed-up the rendering
+ // because we process one column at a time
+ // (and much better and faster to work row-wise, i.e in one scanline)
+ for(int x = 0; x < w; x++)
+ for(int y = 0; y < h; y++)
+ result.setPixel(hofs + y, x, img.pixel(x, y));
+
+ // create the reflection
+ int ht = hs - h - hofs;
+ int hte = ht;
+ for(int x = 0; x < w; x++)
+ for(int y = 0; y < ht; y++)
+ {
+ QRgb color = img.pixel(x, img.height()-y-1);
+ //QRgb565 color = img.scanLine(img.height()-y-1) + x*sizeof(QRgb565); //img.pixel(x, img.height()-y-1);
+ int a = qAlpha(color);
+ int r = qRed(color) * a / 256 * (hte - y) / hte * 3/5;
+ int g = qGreen(color) * a / 256 * (hte - y) / hte * 3/5;
+ int b = qBlue(color) * a / 256 * (hte - y) / hte * 3/5;
+ result.setPixel(h+hofs+y, x, qRgb(r, g, b));
+ }
+
+#ifdef PICTUREFLOW_BILINEAR_FILTER
+ int hh = BILINEAR_STRETCH_VER*hs;
+ int ww = BILINEAR_STRETCH_HOR*w;
+ result = result.scaled(hh, ww, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+#endif
+
+ return result;
+}
+
+
+// get transformed image for specified slide
+// if it does not exist, create it and place it in the cache
+QImage* PictureFlowPrivate::surface(int slideIndex)
+{
+ if(slideIndex < 0)
+ return 0;
+ if(slideIndex >= slideImages.count())
+ return 0;
+
+ if(surfaceCache.contains(slideIndex))
+ return surfaceCache[slideIndex];
+
+ QImage img = widget->slide(slideIndex);
+ if(img.isNull())
+ {
+ if(blankSurface.isNull())
+ {
+ blankSurface = QImage(slideWidth, slideHeight, QImage::Format_RGB16);
+
+ QPainter painter(&blankSurface);
+ QPoint p1(slideWidth*4/10, 0);
+ QPoint p2(slideWidth*6/10, slideHeight);
+ QLinearGradient linearGrad(p1, p2);
+ linearGrad.setColorAt(0, Qt::black);
+ linearGrad.setColorAt(1, Qt::white);
+ painter.setBrush(linearGrad);
+ painter.fillRect(0, 0, slideWidth, slideHeight, QBrush(linearGrad));
+
+ painter.setPen(QPen(QColor(64,64,64), 4));
+ painter.setBrush(QBrush());
+ painter.drawRect(2, 2, slideWidth-3, slideHeight-3);
+ painter.end();
+ blankSurface = prepareSurface(blankSurface, slideWidth, slideHeight);
+ }
+ return &blankSurface;
+ }
+
+ surfaceCache.insert(slideIndex, new QImage(prepareSurface(img, slideWidth, slideHeight)));
+ return surfaceCache[slideIndex];
+}
+
+
+// Schedules rendering the slides. Call this function to avoid immediate
+// render and thus cause less flicker.
+void PictureFlowPrivate::triggerRender()
+{
+ triggerTimer.start();
+}
+
+// Render the slides. Updates only the offscreen buffer.
+void PictureFlowPrivate::render()
+{
+ buffer.fill(0);
+
+ int nleft = leftSlides.count();
+ int nright = rightSlides.count();
+
+ QRect r = renderSlide(centerSlide);
+ int c1 = r.left();
+ int c2 = r.right();
+
+ if(step == 0)
+ {
+ // no animation, boring plain rendering
+ for(int index = 0; index < nleft-1; index++)
+ {
+ int alpha = (index < nleft-2) ? 256 : 128;
+ QRect rs = renderSlide(leftSlides[index], alpha, 0, c1-1);
+ if(!rs.isEmpty())
+ c1 = rs.left();
+ }
+ for(int index = 0; index < nright-1; index++)
+ {
+ int alpha = (index < nright-2) ? 256 : 128;
+ QRect rs = renderSlide(rightSlides[index], alpha, c2+1, buffer.width());
+ if(!rs.isEmpty())
+ c2 = rs.right();
+ }
+
+ QPainter painter;
+ painter.begin(&buffer);
+
+ QFont font("Arial", captionFontSize);
+ font.setBold(true);
+ painter.setFont(font);
+ painter.setPen(Qt::white);
+ //painter.setPen(QColor(255,255,255,127));
+
+ if (!captions.isEmpty())
+ painter.drawText( QRect(0,0, buffer.width(), (buffer.height() - slideSize().height())/4),
+ Qt::AlignCenter, captions[centerIndex]);
+
+ painter.end();
+
+ }
+ else
+ {
+ // the first and last slide must fade in/fade out
+ for(int index = 0; index < nleft; index++)
+ {
+ int alpha = 256;
+ if(index == nleft-1)
+ alpha = (step > 0) ? 0 : 128-fade/2;
+ if(index == nleft-2)
+ alpha = (step > 0) ? 128-fade/2 : 256-fade/2;
+ if(index == nleft-3)
+ alpha = (step > 0) ? 256-fade/2 : 256;
+ QRect rs = renderSlide(leftSlides[index], alpha, 0, c1-1);
+ if(!rs.isEmpty())
+ c1 = rs.left();
+
+ alpha = (step > 0) ? 256-fade/2 : 256;
+ }
+ for(int index = 0; index < nright; index++)
+ {
+ int alpha = (index < nright-2) ? 256 : 128;
+ if(index == nright-1)
+ alpha = (step > 0) ? fade/2 : 0;
+ if(index == nright-2)
+ alpha = (step > 0) ? 128+fade/2 : fade/2;
+ if(index == nright-3)
+ alpha = (step > 0) ? 256 : 128+fade/2;
+ QRect rs = renderSlide(rightSlides[index], alpha, c2+1, buffer.width());
+ if(!rs.isEmpty())
+ c2 = rs.right();
+ }
+
+
+
+ QPainter painter;
+ painter.begin(&buffer);
+
+ QFont font("Arial", captionFontSize);
+ font.setBold(true);
+ painter.setFont(font);
+
+ int leftTextIndex = (step>0) ? centerIndex : centerIndex-1;
+
+ painter.setPen(QColor(255,255,255, (255-fade) ));
+ painter.drawText( QRect(0,0, buffer.width(), (buffer.height() - slideSize().height())/4),
+ Qt::AlignCenter, captions[leftTextIndex]);
+
+ painter.setPen(QColor(255,255,255, fade));
+ painter.drawText( QRect(0,0, buffer.width(), (buffer.height() - slideSize().height())/4),
+ Qt::AlignCenter, captions[leftTextIndex+1]);
+
+
+ painter.end();
+ }
+}
+
+
+static inline uint BYTE_MUL_RGB16(uint x, uint a) {
+ a += 1;
+ uint t = (((x & 0x07e0)*a) >> 8) & 0x07e0;
+ t |= (((x & 0xf81f)*(a>>2)) >> 6) & 0xf81f;
+ return t;
+}
+
+static inline uint BYTE_MUL_RGB16_32(uint x, uint a) {
+ uint t = (((x & 0xf81f07e0) >> 5)*a) & 0xf81f07e0;
+ t |= (((x & 0x07e0f81f)*a) >> 5) & 0x07e0f81f;
+ return t;
+}
+
+
+// Renders a slide to offscreen buffer. Returns a rect of the rendered area.
+// alpha=256 means normal, alpha=0 is fully black, alpha=128 half transparent
+// col1 and col2 limit the column for rendering.
+QRect PictureFlowPrivate::renderSlide(const SlideInfo &slide, int alpha,
+int col1, int col2)
+{
+ QImage* src = surface(slide.slideIndex);
+ if(!src)
+ return QRect();
+
+ QRect rect(0, 0, 0, 0);
+
+#ifdef PICTUREFLOW_BILINEAR_FILTER
+ int sw = src->height() / BILINEAR_STRETCH_HOR;
+ int sh = src->width() / BILINEAR_STRETCH_VER;
+#else
+ int sw = src->height();
+ int sh = src->width();
+#endif
+ int h = buffer.height();
+ int w = buffer.width();
+
+ if(col1 > col2)
+ {
+ int c = col2;
+ col2 = col1;
+ col1 = c;
+ }
+
+ col1 = (col1 >= 0) ? col1 : 0;
+ col2 = (col2 >= 0) ? col2 : w-1;
+ col1 = qMin(col1, w-1);
+ col2 = qMin(col2, w-1);
+
+ int distance = h * 100 / zoom;
+ PFreal sdx = fcos(slide.angle);
+ PFreal sdy = fsin(slide.angle);
+ PFreal xs = slide.cx - slideWidth * sdx/2;
+ PFreal ys = slide.cy - slideWidth * sdy/2;
+ PFreal dist = distance * PFREAL_ONE;
+
+ int xi = qMax((PFreal)0, ((w*PFREAL_ONE/2) + fdiv(xs*h, dist+ys)) >> PFREAL_SHIFT);
+ if(xi >= w)
+ return rect;
+
+ bool flag = false;
+ rect.setLeft(xi);
+ for(int x = qMax(xi, col1); x <= col2; x++)
+ {
+ PFreal hity = 0;
+ PFreal fk = rays[x];
+ if(sdy)
+ {
+ fk = fk - fdiv(sdx,sdy);
+ hity = -fdiv((rays[x]*distance - slide.cx + slide.cy*sdx/sdy), fk);
+ }
+
+ dist = distance*PFREAL_ONE + hity;
+ if(dist < 0)
+ continue;
+
+ PFreal hitx = fmul(dist, rays[x]);
+ PFreal hitdist = fdiv(hitx - slide.cx, sdx);
+
+#ifdef PICTUREFLOW_BILINEAR_FILTER
+ int column = sw*BILINEAR_STRETCH_HOR/2 + (hitdist*BILINEAR_STRETCH_HOR >> PFREAL_SHIFT);
+ if(column >= sw*BILINEAR_STRETCH_HOR)
+ break;
+#else
+ int column = sw/2 + (hitdist >> PFREAL_SHIFT);
+ if(column >= sw)
+ break;
+#endif
+ if(column < 0)
+ continue;
+
+ rect.setRight(x);
+ if(!flag)
+ rect.setLeft(x);
+ flag = true;
+
+ int y1 = h/2;
+ int y2 = y1+ 1;
+ QRgb565* pixel1 = (QRgb565*)(buffer.scanLine(y1)) + x;
+ QRgb565* pixel2 = (QRgb565*)(buffer.scanLine(y2)) + x;
+ int pixelstep = pixel2 - pixel1;
+
+#ifdef PICTUREFLOW_BILINEAR_FILTER
+ int center = (sh*BILINEAR_STRETCH_VER/2);
+ int dy = dist*BILINEAR_STRETCH_VER / h;
+#else
+ int center = (sh/2);
+ int dy = dist / h;
+#endif
+ int p1 = center*PFREAL_ONE - dy/2;
+ int p2 = center*PFREAL_ONE + dy/2;
+
+ const QRgb565 *ptr = (const QRgb565*)(src->scanLine(column));
+ if(alpha == 256)
+ while((y1 >= 0) && (y2 < h) && (p1 >= 0))
+ {
+ *pixel1 = ptr[p1 >> PFREAL_SHIFT];
+ *pixel2 = ptr[p2 >> PFREAL_SHIFT];
+ p1 -= dy;
+ p2 += dy;
+ y1--;
+ y2++;
+ pixel1 -= pixelstep;
+ pixel2 += pixelstep;
+ }
+ else
+ while((y1 >= 0) && (y2 < h) && (p1 >= 0))
+ {
+ QRgb565 c1 = ptr[p1 >> PFREAL_SHIFT];
+ QRgb565 c2 = ptr[p2 >> PFREAL_SHIFT];
+
+ *pixel1 = BYTE_MUL_RGB16(c1, alpha);
+ *pixel2 = BYTE_MUL_RGB16(c2, alpha);
+
+/*
+ int r1 = qRed(c1) * alpha/256;
+ int g1 = qGreen(c1) * alpha/256;
+ int b1 = qBlue(c1) * alpha/256;
+ int r2 = qRed(c2) * alpha/256;
+ int g2 = qGreen(c2) * alpha/256;
+ int b2 = qBlue(c2) * alpha/256;
+ *pixel1 = qRgb(r1, g1, b1);
+ *pixel2 = qRgb(r2, g2, b2);
+*/
+ p1 -= dy;
+ p2 += dy;
+ y1--;
+ y2++;
+ pixel1 -= pixelstep;
+ pixel2 += pixelstep;
+ }
+ }
+
+ rect.setTop(0);
+ rect.setBottom(h-1);
+ return rect;
+}
+
+// Updates look-up table and other stuff necessary for the rendering.
+// Call this when the viewport size or slide dimension is changed.
+void PictureFlowPrivate::recalc(int ww, int wh)
+{
+ int w = (ww+1)/2;
+ int h = (wh+1)/2;
+ buffer = QImage(ww, wh, QImage::Format_RGB16);
+ buffer.fill(0);
+
+ rays.resize(w*2);
+
+ for(int i = 0; i < w; i++)
+ {
+ PFreal gg = (PFREAL_HALF + i * PFREAL_ONE) / (2*h);
+ rays[w-i-1] = -gg;
+ rays[w+i] = gg;
+ }
+
+ // pointer must move more than 1/15 of the window to enter drag mode
+ singlePressThreshold = ww / 15;
+// qDebug() << "singlePressThreshold now set to " << singlePressThreshold;
+
+ pixelsToMovePerSlide = ww / 3;
+// qDebug() << "pixelsToMovePerSlide now set to " << pixelsToMovePerSlide;
+
+ itilt = 80 * IANGLE_MAX / 360; // approx. 80 degrees tilted
+
+ offsetY = slideWidth/2 * fsin(itilt);
+ offsetY += slideWidth * PFREAL_ONE / 4;
+
+// offsetX = slideWidth/2 * (PFREAL_ONE-fcos(itilt));
+// offsetX += slideWidth * PFREAL_ONE;
+
+ // center slide + side slide
+ offsetX = slideWidth*PFREAL_ONE;
+// offsetX = 150*PFREAL_ONE;//(slideWidth/2)*PFREAL_ONE + ( slideWidth*fcos(itilt) )/2;
+// qDebug() << "center width = " << slideWidth;
+// qDebug() << "side width = " << fixedToFloat(slideWidth/2 * (PFREAL_ONE-fcos(itilt)));
+// qDebug() << "offsetX now " << fixedToFloat(offsetX);
+
+ spacing = slideWidth/5;
+
+ surfaceCache.clear();
+ blankSurface = QImage();
+}
+
+void PictureFlowPrivate::startAnimation()
+{
+ if(!animateTimer.isActive())
+ {
+ step = (target < centerSlide.slideIndex) ? -1 : 1;
+ animateTimer.start(30, widget);
+ }
+}
+
+// Updates the animation effect. Call this periodically from a timer.
+void PictureFlowPrivate::updateAnimation()
+{
+ if(!animateTimer.isActive())
+ return;
+ if(step == 0)
+ return;
+
+ int speed = 16384;
+
+ // deaccelerate when approaching the target
+ if(true)
+ {
+ const int max = 2 * 65536;
+
+ int fi = slideFrame;
+ fi -= (target << 16);
+ if(fi < 0)
+ fi = -fi;
+ fi = qMin(fi, max);
+
+ int ia = IANGLE_MAX * (fi-max/2) / (max*2);
+ speed = 512 + 16384 * (PFREAL_ONE+fsin(ia))/PFREAL_ONE;
+ }
+
+ slideFrame += speed*step;
+
+ int index = slideFrame >> 16;
+ int pos = slideFrame & 0xffff;
+ int neg = 65536 - pos;
+ int tick = (step < 0) ? neg : pos;
+ PFreal ftick = (tick * PFREAL_ONE) >> 16;
+
+ // the leftmost and rightmost slide must fade away
+ fade = pos / 256;
+
+ if(step < 0)
+ index++;
+ if(centerIndex != index)
+ {
+ centerIndex = index;
+ slideFrame = index << 16;
+ centerSlide.slideIndex = centerIndex;
+ for(int i = 0; i < leftSlides.count(); i++)
+ leftSlides[i].slideIndex = centerIndex-1-i;
+ for(int i = 0; i < rightSlides.count(); i++)
+ rightSlides[i].slideIndex = centerIndex+1+i;
+ }
+
+ centerSlide.angle = (step * tick * itilt) >> 16;
+ centerSlide.cx = -step * fmul(offsetX, ftick);
+ centerSlide.cy = fmul(offsetY, ftick);
+
+ if(centerIndex == target)
+ {
+ resetSlides();
+ animateTimer.stop();
+ triggerRender();
+ step = 0;
+ fade = 256;
+ return;
+ }
+
+ for(int i = 0; i < leftSlides.count(); i++)
+ {
+ SlideInfo& si = leftSlides[i];
+ si.angle = itilt;
+ si.cx = -(offsetX + spacing*i*PFREAL_ONE + step*spacing*ftick);
+ si.cy = offsetY;
+ }
+
+ for(int i = 0; i < rightSlides.count(); i++)
+ {
+ SlideInfo& si = rightSlides[i];
+ si.angle = -itilt;
+ si.cx = offsetX + spacing*i*PFREAL_ONE - step*spacing*ftick;
+ si.cy = offsetY;
+ }
+
+ if(step > 0)
+ {
+ PFreal ftick = (neg * PFREAL_ONE) >> 16;
+ rightSlides[0].angle = -(neg * itilt) >> 16;
+ rightSlides[0].cx = fmul(offsetX, ftick);
+ rightSlides[0].cy = fmul(offsetY, ftick);
+ }
+ else
+ {
+ PFreal ftick = (pos * PFREAL_ONE) >> 16;
+ leftSlides[0].angle = (pos * itilt) >> 16;
+ leftSlides[0].cx = -fmul(offsetX, ftick);
+ leftSlides[0].cy = fmul(offsetY, ftick);
+ }
+
+ // must change direction ?
+ if(target < index) if(step > 0)
+ step = -1;
+ if(target > index) if(step < 0)
+ step = 1;
+
+ triggerRender();
+}
+
+
+void PictureFlowPrivate::clearSurfaceCache()
+{
+ surfaceCache.clear();
+}
+
+// -----------------------------------------
+
+PictureFlow::PictureFlow(QWidget* parent): QWidget(parent)
+{
+ d = new PictureFlowPrivate(this);
+
+ setAttribute(Qt::WA_StaticContents, true);
+ setAttribute(Qt::WA_OpaquePaintEvent, true);
+ setAttribute(Qt::WA_NoSystemBackground, true);
+
+#ifdef Q_WS_QWS
+ if (QScreen::instance()->pixelFormat() != QImage::Format_Invalid)
+ setAttribute(Qt::WA_PaintOnScreen, true);
+#endif
+}
+
+PictureFlow::~PictureFlow()
+{
+ delete d;
+}
+
+int PictureFlow::slideCount() const
+{
+ return d->slideCount();
+}
+
+void PictureFlow::setSlideCount(int count)
+{
+ d->setSlideCount(count);
+}
+
+QSize PictureFlow::slideSize() const
+{
+ return d->slideSize();
+}
+
+void PictureFlow::setSlideSize(QSize size)
+{
+ d->setSlideSize(size);
+}
+
+int PictureFlow::zoomFactor() const
+{
+ return d->zoomFactor();
+}
+
+void PictureFlow::setZoomFactor(int z)
+{
+ d->setZoomFactor(z);
+}
+
+QImage PictureFlow::slide(int index) const
+{
+ return d->slide(index);
+}
+
+void PictureFlow::setSlide(int index, const QImage& image)
+{
+ d->setSlide(index, image);
+}
+
+void PictureFlow::setSlide(int index, const QPixmap& pixmap)
+{
+ d->setSlide(index, pixmap.toImage());
+}
+
+void PictureFlow::setSlideCaption(int index, QString caption)
+{
+ d->captions[index] = caption;
+}
+
+
+int PictureFlow::currentSlide() const
+{
+ return d->currentSlide();
+}
+
+void PictureFlow::setCurrentSlide(int index)
+{
+ d->setCurrentSlide(index);
+}
+
+void PictureFlow::clear()
+{
+ d->setSlideCount(0);
+}
+
+void PictureFlow::clearCaches()
+{
+ d->clearSurfaceCache();
+}
+
+void PictureFlow::render()
+{
+ d->render();
+ update();
+}
+
+void PictureFlow::showPrevious()
+{
+ d->showPrevious();
+}
+
+void PictureFlow::showNext()
+{
+ d->showNext();
+}
+
+void PictureFlow::showSlide(int index)
+{
+ d->showSlide(index);
+}
+
+void PictureFlow::keyPressEvent(QKeyEvent* event)
+{
+ if(event->key() == Qt::Key_Left)
+ {
+ if(event->modifiers() == Qt::ControlModifier)
+ showSlide(currentSlide()-10);
+ else
+ showPrevious();
+ event->accept();
+ return;
+ }
+
+ if(event->key() == Qt::Key_Right)
+ {
+ if(event->modifiers() == Qt::ControlModifier)
+ showSlide(currentSlide()+10);
+ else
+ showNext();
+ event->accept();
+ return;
+ }
+
+ if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Select) {
+ emit itemActivated(d->getTarget());
+ event->accept();
+ return;
+ }
+
+ event->ignore();
+}
+
+#define SPEED_LOWER_THRESHOLD 10
+#define SPEED_UPPER_LIMIT 40
+
+void PictureFlow::mouseMoveEvent(QMouseEvent* event)
+{
+ int distanceMovedSinceLastEvent = event->pos().x() - d->previousPos.x();
+
+ // Check to see if we need to switch from single press mode to a drag mode
+ if (d->singlePress)
+ {
+ // Increment the distance moved for this event
+ d->pixelDistanceMoved += distanceMovedSinceLastEvent;
+
+ // Check against threshold
+ if (qAbs(d->pixelDistanceMoved) > d->singlePressThreshold)
+ {
+ d->singlePress = false;
+// qDebug() << "DRAG MODE ON";
+ }
+ }
+
+ if (!d->singlePress)
+ {
+ int speed;
+ // Calculate velocity in a 10th of a window width per second
+ if (d->previousPosTimestamp.elapsed() == 0)
+ speed = SPEED_LOWER_THRESHOLD;
+ else
+ {
+ speed = ((qAbs(event->pos().x()-d->previousPos.x())*1000) / d->previousPosTimestamp.elapsed())
+ / (d->buffer.width() / 10);
+
+ if (speed < SPEED_LOWER_THRESHOLD)
+ speed = SPEED_LOWER_THRESHOLD;
+ else if (speed > SPEED_UPPER_LIMIT)
+ speed = SPEED_UPPER_LIMIT;
+ else {
+ speed = SPEED_LOWER_THRESHOLD + (speed / 3);
+// qDebug() << "ACCELERATION ENABLED Speed = " << speed << ", Distance = " << distanceMovedSinceLastEvent;
+
+ }
+ }
+
+
+// qDebug() << "Speed = " << speed;
+
+// int incr = ((event->pos().x() - d->previousPos.x())/10) * speed;
+
+// qDebug() << "Incremented by " << incr;
+
+ int incr = (distanceMovedSinceLastEvent * speed);
+
+ //qDebug() << "(distanceMovedSinceLastEvent * speed) = " << incr;
+
+ if (incr > d->pixelsToMovePerSlide*2) {
+ incr = d->pixelsToMovePerSlide*2;
+ //qDebug() << "Limiting incr to " << incr;
+ }
+
+
+ d->pixelDistanceMoved += (distanceMovedSinceLastEvent * speed);
+ // qDebug() << "distance: " << d->pixelDistanceMoved;
+
+ int slideInc;
+
+ slideInc = d->pixelDistanceMoved / (d->pixelsToMovePerSlide * 10);
+
+ if (slideInc != 0) {
+ int targetSlide = d->getTarget() - slideInc;
+ showSlide(targetSlide);
+// qDebug() << "TargetSlide = " << targetSlide;
+
+ //qDebug() << "Decrementing pixelDistanceMoved by " << (d->pixelsToMovePerSlide *10) * slideInc;
+
+ d->pixelDistanceMoved -= (d->pixelsToMovePerSlide *10) * slideInc;
+
+/*
+ if ( (targetSlide <= 0) || (targetSlide >= d->slideCount()-1) )
+ d->pixelDistanceMoved = 0;
+*/
+ }
+
+
+ }
+
+ d->previousPos = event->pos();
+ d->previousPosTimestamp.restart();
+
+ emit inputReceived();
+}
+
+void PictureFlow::mousePressEvent(QMouseEvent* event)
+{
+ d->firstPress = event->pos();
+ d->previousPos = event->pos();
+ d->previousPosTimestamp.start();
+ d->singlePress = true; // Initially assume a single press
+// d->dragStartSlide = d->getTarget();
+ d->pixelDistanceMoved = 0;
+
+ emit inputReceived();
+}
+
+void PictureFlow::mouseReleaseEvent(QMouseEvent* event)
+{
+ int sideWidth = (d->buffer.width() - slideSize().width()) /2;
+
+ if (d->singlePress)
+ {
+ if (event->x() < sideWidth )
+ {
+ showPrevious();
+ } else if ( event->x() > sideWidth + slideSize().width() ) {
+ showNext();
+ } else {
+ emit itemActivated(d->getTarget());
+ }
+
+ event->accept();
+ }
+
+ emit inputReceived();
+}
+
+
+void PictureFlow::paintEvent(QPaintEvent* event)
+{
+ Q_UNUSED(event);
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ painter.drawImage(QPoint(0,0), d->buffer);
+}
+
+void PictureFlow::resizeEvent(QResizeEvent* event)
+{
+ d->resize(width(), height());
+ QWidget::resizeEvent(event);
+}
+
+void PictureFlow::timerEvent(QTimerEvent* event)
+{
+ if(event->timerId() == d->animateTimer.timerId())
+ {
+// QTime now = QTime::currentTime();
+ d->updateAnimation();
+// d->animateTimer.start(qMax(0, 30-now.elapsed() ), this);
+ }
+ else
+ QWidget::timerEvent(event);
+}
diff --git a/demos/embedded/fluidlauncher/pictureflow.h b/demos/embedded/fluidlauncher/pictureflow.h
new file mode 100644
index 0000000..fccc7a3
--- /dev/null
+++ b/demos/embedded/fluidlauncher/pictureflow.h
@@ -0,0 +1,237 @@
+/****************************************************************************
+*
+* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+* This is version of the Pictureflow animated image show widget modified by Nokia.
+*
+* $QT_BEGIN_LICENSE:LGPL$
+* No Commercial Usage
+* This file contains pre-release code and may not be distributed.
+* You may use this file in accordance with the terms and conditions
+* contained in the either Technology Preview License Agreement or the
+* Beta Release License Agreement.
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this file may be used under the terms of the GNU Lesser
+* General Public License version 2.1 as published by the Free Software
+* Foundation and appearing in the file LICENSE.LGPL included in the
+* packaging of this file. Please review the following information to
+* ensure the GNU Lesser General Public License version 2.1 requirements
+* will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+*
+* In addition, as a special exception, Nokia gives you certain
+* additional rights. These rights are described in the Nokia Qt LGPL
+* Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+* package.
+*
+* GNU General Public License Usage
+* Alternatively, this file may be used under the terms of the GNU
+* General Public License version 3.0 as published by the Free Software
+* Foundation and appearing in the file LICENSE.GPL included in the
+* packaging of this file. Please review the following information to
+* ensure the GNU General Public License version 3.0 requirements will be
+* met: http://www.gnu.org/copyleft/gpl.html.
+*
+* If you are unsure which license is appropriate for your use, please
+* contact the sales department at qt-sales@nokia.com.
+* $QT_END_LICENSE$
+*
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of the <organization> nor the
+* names of its contributors may be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY TROLLTECH ASA ``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 <copyright holder> 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.
+
+****************************************************************************/
+/*
+ ORIGINAL COPYRIGHT HEADER
+ PictureFlow - animated image show widget
+ http://pictureflow.googlecode.com
+
+ Copyright (C) 2007 Ariya Hidayat (ariya@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 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 PICTUREFLOW_H
+#define PICTUREFLOW_H
+
+#include <QWidget>
+
+class PictureFlowPrivate;
+
+/*!
+ Class PictureFlow implements an image show widget with animation effect
+ like Apple's CoverFlow (in iTunes and iPod). Images are arranged in form
+ of slides, one main slide is shown at the center with few slides on
+ the left and right sides of the center slide. When the next or previous
+ slide is brought to the front, the whole slides flow to the right or
+ the right with smooth animation effect; until the new slide is finally
+ placed at the center.
+
+ */
+class PictureFlow : public QWidget
+{
+Q_OBJECT
+
+ Q_PROPERTY(int slideCount READ slideCount WRITE setSlideCount)
+ Q_PROPERTY(int currentSlide READ currentSlide WRITE setCurrentSlide)
+ Q_PROPERTY(QSize slideSize READ slideSize WRITE setSlideSize)
+ Q_PROPERTY(int zoomFactor READ zoomFactor WRITE setZoomFactor)
+
+public:
+ /*!
+ Creates a new PictureFlow widget.
+ */
+ PictureFlow(QWidget* parent = 0);
+
+ /*!
+ Destroys the widget.
+ */
+ ~PictureFlow();
+
+ /*!
+ Returns the total number of slides.
+ */
+ int slideCount() const;
+
+ /*!
+ Sets the total number of slides.
+ */
+ void setSlideCount(int count);
+
+ /*!
+ Returns the dimension of each slide (in pixels).
+ */
+ QSize slideSize() const;
+
+ /*!
+ Sets the dimension of each slide (in pixels).
+ */
+ void setSlideSize(QSize size);
+
+ /*!
+ Sets the zoom factor (in percent).
+ */
+ void setZoomFactor(int zoom);
+
+ /*!
+ Returns the zoom factor (in percent).
+ */
+ int zoomFactor() const;
+
+ /*!
+ Clears any caches held to free up memory
+ */
+ void clearCaches();
+
+ /*!
+ Returns QImage of specified slide.
+ This function will be called only whenever necessary, e.g. the 100th slide
+ will not be retrived when only the first few slides are visible.
+ */
+ virtual QImage slide(int index) const;
+
+ /*!
+ Sets an image for specified slide. If the slide already exists,
+ it will be replaced.
+ */
+ virtual void setSlide(int index, const QImage& image);
+
+ virtual void setSlideCaption(int index, QString caption);
+
+ /*!
+ Sets a pixmap for specified slide. If the slide already exists,
+ it will be replaced.
+ */
+ virtual void setSlide(int index, const QPixmap& pixmap);
+
+ /*!
+ Returns the index of slide currently shown in the middle of the viewport.
+ */
+ int currentSlide() const;
+
+public slots:
+
+ /*!
+ Sets slide to be shown in the middle of the viewport. No animation
+ effect will be produced, unlike using showSlide.
+ */
+ void setCurrentSlide(int index);
+
+ /*!
+ Clears images of all slides.
+ */
+ void clear();
+
+ /*!
+ Rerender the widget. Normally this function will be automatically invoked
+ whenever necessary, e.g. during the transition animation.
+ */
+ void render();
+
+ /*!
+ Shows previous slide using animation effect.
+ */
+ void showPrevious();
+
+ /*!
+ Shows next slide using animation effect.
+ */
+ void showNext();
+
+ /*!
+ Go to specified slide using animation effect.
+ */
+ void showSlide(int index);
+
+signals:
+ void itemActivated(int index);
+ void inputReceived();
+
+protected:
+ void paintEvent(QPaintEvent *event);
+ void keyPressEvent(QKeyEvent* event);
+ void mouseMoveEvent(QMouseEvent* event);
+ void mousePressEvent(QMouseEvent* event);
+ void mouseReleaseEvent(QMouseEvent* event);
+ void resizeEvent(QResizeEvent* event);
+ void timerEvent(QTimerEvent* event);
+
+private:
+ PictureFlowPrivate* d;
+};
+
+#endif // PICTUREFLOW_H
diff --git a/demos/embedded/fluidlauncher/screenshots/concentriccircles.png b/demos/embedded/fluidlauncher/screenshots/concentriccircles.png
new file mode 100644
index 0000000..fd308b5
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/concentriccircles.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/screenshots/context2d.png b/demos/embedded/fluidlauncher/screenshots/context2d.png
new file mode 100644
index 0000000..d571546
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/context2d.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/screenshots/deform.png b/demos/embedded/fluidlauncher/screenshots/deform.png
new file mode 100644
index 0000000..c22f2ae
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/deform.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/screenshots/desktopservices.png b/demos/embedded/fluidlauncher/screenshots/desktopservices.png
new file mode 100644
index 0000000..a8d82ce
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/desktopservices.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/screenshots/elasticnodes.png b/demos/embedded/fluidlauncher/screenshots/elasticnodes.png
new file mode 100644
index 0000000..bc157e5
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/elasticnodes.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/screenshots/embeddedsvgviewer.png b/demos/embedded/fluidlauncher/screenshots/embeddedsvgviewer.png
new file mode 100644
index 0000000..522f13b
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/embeddedsvgviewer.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/screenshots/fridgemagnets.png b/demos/embedded/fluidlauncher/screenshots/fridgemagnets.png
new file mode 100644
index 0000000..87b9099
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/fridgemagnets.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/screenshots/ftp.png b/demos/embedded/fluidlauncher/screenshots/ftp.png
new file mode 100644
index 0000000..fae7ffc
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/ftp.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/screenshots/mediaplayer.png b/demos/embedded/fluidlauncher/screenshots/mediaplayer.png
new file mode 100644
index 0000000..1304a19
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/mediaplayer.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/screenshots/pathstroke.png b/demos/embedded/fluidlauncher/screenshots/pathstroke.png
new file mode 100644
index 0000000..c3d727e
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/pathstroke.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/screenshots/saxbookmarks.png b/demos/embedded/fluidlauncher/screenshots/saxbookmarks.png
new file mode 100644
index 0000000..6a2b07f
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/saxbookmarks.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/screenshots/styledemo.png b/demos/embedded/fluidlauncher/screenshots/styledemo.png
new file mode 100644
index 0000000..669c488
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/styledemo.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/screenshots/wiggly.png b/demos/embedded/fluidlauncher/screenshots/wiggly.png
new file mode 100644
index 0000000..b20fbc4
--- /dev/null
+++ b/demos/embedded/fluidlauncher/screenshots/wiggly.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/slides/demo_1.png b/demos/embedded/fluidlauncher/slides/demo_1.png
new file mode 100644
index 0000000..d2952e5
--- /dev/null
+++ b/demos/embedded/fluidlauncher/slides/demo_1.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/slides/demo_2.png b/demos/embedded/fluidlauncher/slides/demo_2.png
new file mode 100644
index 0000000..1899825
--- /dev/null
+++ b/demos/embedded/fluidlauncher/slides/demo_2.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/slides/demo_3.png b/demos/embedded/fluidlauncher/slides/demo_3.png
new file mode 100644
index 0000000..8369bc0
--- /dev/null
+++ b/demos/embedded/fluidlauncher/slides/demo_3.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/slides/demo_4.png b/demos/embedded/fluidlauncher/slides/demo_4.png
new file mode 100644
index 0000000..377e369
--- /dev/null
+++ b/demos/embedded/fluidlauncher/slides/demo_4.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/slides/demo_5.png b/demos/embedded/fluidlauncher/slides/demo_5.png
new file mode 100644
index 0000000..239f08a
--- /dev/null
+++ b/demos/embedded/fluidlauncher/slides/demo_5.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/slides/demo_6.png b/demos/embedded/fluidlauncher/slides/demo_6.png
new file mode 100644
index 0000000..0addf37
--- /dev/null
+++ b/demos/embedded/fluidlauncher/slides/demo_6.png
Binary files differ
diff --git a/demos/embedded/fluidlauncher/slideshow.cpp b/demos/embedded/fluidlauncher/slideshow.cpp
new file mode 100644
index 0000000..8f643b4
--- /dev/null
+++ b/demos/embedded/fluidlauncher/slideshow.cpp
@@ -0,0 +1,233 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QBasicTimer>
+#include <QList>
+#include <QImage>
+#include <QDir>
+#include <QPainter>
+#include <QPaintEvent>
+
+#include <QDebug>
+
+
+#include "slideshow.h"
+
+
+class SlideShowPrivate
+{
+public:
+ SlideShowPrivate();
+
+ int currentSlide;
+ int slideInterval;
+ QBasicTimer interSlideTimer;
+ QStringList imagePaths;
+
+ void showNextSlide();
+};
+
+
+
+SlideShowPrivate::SlideShowPrivate()
+{
+ currentSlide = 0;
+ slideInterval = 10000; // Default to 10 sec interval
+}
+
+
+void SlideShowPrivate::showNextSlide()
+{
+ currentSlide++;
+ if (currentSlide >= imagePaths.size())
+ currentSlide = 0;
+}
+
+
+
+SlideShow::SlideShow()
+{
+ d = new SlideShowPrivate;
+
+ setAttribute(Qt::WA_StaticContents, true);
+ setAttribute(Qt::WA_OpaquePaintEvent, true);
+ setAttribute(Qt::WA_NoSystemBackground, true);
+
+ setMouseTracking(true);
+}
+
+
+SlideShow::~SlideShow()
+{
+ delete d;
+}
+
+
+void SlideShow::addImageDir(QString dirName)
+{
+ QDir dir(dirName);
+
+ QStringList fileNames = dir.entryList(QDir::Files | QDir::Readable, QDir::Name);
+
+ for (int i=0; i<fileNames.count(); i++)
+ d->imagePaths << dir.absoluteFilePath(fileNames[i]);
+}
+
+void SlideShow::addImage(QString filename)
+{
+ d->imagePaths << filename;
+}
+
+
+void SlideShow::clearImages()
+{
+ d->imagePaths.clear();
+}
+
+
+void SlideShow::startShow()
+{
+ showFullScreen();
+ d->interSlideTimer.start(d->slideInterval, this);
+ d->showNextSlide();
+ update();
+}
+
+
+void SlideShow::stopShow()
+{
+ hide();
+ d->interSlideTimer.stop();
+}
+
+
+int SlideShow::slideInterval()
+{
+ return d->slideInterval;
+}
+
+void SlideShow::setSlideInterval(int val)
+{
+ d->slideInterval = val;
+}
+
+
+void SlideShow::timerEvent(QTimerEvent* event)
+{
+ Q_UNUSED(event);
+ d->showNextSlide();
+ update();
+}
+
+
+void SlideShow::paintEvent(QPaintEvent *event)
+{
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::Antialiasing, false);
+
+ if (d->imagePaths.size() > 0) {
+ QPixmap slide = QPixmap(d->imagePaths[d->currentSlide]);
+ QSize slideSize = slide.size();
+ QSize scaledSize = QSize(qMin(slideSize.width(), size().width()),
+ qMin(slideSize.height(), size().height()));
+ if (slideSize != scaledSize)
+ slide = slide.scaled(scaledSize, Qt::KeepAspectRatio);
+
+ QRect pixmapRect(qMax( (size().width() - slide.width())/2, 0),
+ qMax( (size().height() - slide.height())/2, 0),
+ slide.width(),
+ slide.height());
+
+ if (pixmapRect.top() > 0) {
+ // Fill in top & bottom rectangles:
+ painter.fillRect(0, 0, size().width(), pixmapRect.top(), Qt::black);
+ painter.fillRect(0, pixmapRect.bottom(), size().width(), size().height(), Qt::black);
+ }
+
+ if (pixmapRect.left() > 0) {
+ // Fill in left & right rectangles:
+ painter.fillRect(0, 0, pixmapRect.left(), size().height(), Qt::black);
+ painter.fillRect(pixmapRect.right(), 0, size().width(), size().height(), Qt::black);
+ }
+
+ painter.drawPixmap(pixmapRect, slide);
+
+ } else
+ painter.fillRect(event->rect(), Qt::black);
+}
+
+
+void SlideShow::keyPressEvent(QKeyEvent* event)
+{
+ Q_UNUSED(event);
+ emit inputReceived();
+}
+
+
+void SlideShow::mouseMoveEvent(QMouseEvent* event)
+{
+ Q_UNUSED(event);
+ emit inputReceived();
+}
+
+
+void SlideShow::mousePressEvent(QMouseEvent* event)
+{
+ Q_UNUSED(event);
+ emit inputReceived();
+}
+
+
+void SlideShow::mouseReleaseEvent(QMouseEvent* event)
+{
+ Q_UNUSED(event);
+ emit inputReceived();
+}
+
+
+void SlideShow::showEvent(QShowEvent * event )
+{
+ Q_UNUSED(event);
+#ifndef QT_NO_CURSOR
+ setCursor(Qt::BlankCursor);
+#endif
+}
+
diff --git a/demos/embedded/fluidlauncher/slideshow.h b/demos/embedded/fluidlauncher/slideshow.h
new file mode 100644
index 0000000..27fb87b
--- /dev/null
+++ b/demos/embedded/fluidlauncher/slideshow.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SLIDESHOW_H
+#define SLIDESHOW_H
+
+#include <QWidget>
+
+class SlideShowPrivate;
+
+class SlideShow : public QWidget
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int slideInterval READ slideInterval WRITE setSlideInterval)
+
+public:
+ SlideShow();
+ ~SlideShow();
+ void addImage(QString filename);
+ void addImageDir(QString dirName);
+ void clearImages();
+ void startShow();
+ void stopShow();
+
+
+ int slideInterval();
+ void setSlideInterval(int val);
+
+signals:
+ void inputReceived();
+
+protected:
+ void paintEvent(QPaintEvent *event);
+ void keyPressEvent(QKeyEvent* event);
+ void mouseMoveEvent(QMouseEvent* event);
+ void mousePressEvent(QMouseEvent* event);
+ void mouseReleaseEvent(QMouseEvent* event);
+ void timerEvent(QTimerEvent* event);
+ void showEvent(QShowEvent * event );
+
+
+private:
+ SlideShowPrivate* d;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif
diff --git a/demos/embedded/styledemo/files/add.png b/demos/embedded/styledemo/files/add.png
new file mode 100755
index 0000000..fc5c16d
--- /dev/null
+++ b/demos/embedded/styledemo/files/add.png
Binary files differ
diff --git a/demos/embedded/styledemo/files/application.qss b/demos/embedded/styledemo/files/application.qss
new file mode 100644
index 0000000..432fe6b
--- /dev/null
+++ b/demos/embedded/styledemo/files/application.qss
@@ -0,0 +1,125 @@
+QWidget#StyleWidget
+{
+ background-color: none;
+ background-image: url(icons:nature_1.jpg);
+}
+
+QLabel, QAbstractButton
+{
+ font: bold;
+ color: beige;
+}
+
+QAbstractButton
+{
+ background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(173,216,230,60%), stop:1 rgba(0,0,139,60%) );
+ border-color: black;
+ border-style: solid;
+ border-width: 3px;
+ border-radius: 6px;
+}
+
+QAbstractButton:pressed, QAbstractButton:checked
+{
+ background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(0,0,139,60%), stop:1 rgba(173,216,230,60%) );
+}
+
+QSpinBox {
+ padding-left: 24px;
+ padding-right: 24px;
+ border-color: darkkhaki;
+ border-style: solid;
+ border-radius: 5;
+ border-width: 3;
+}
+
+QSpinBox::up-button
+{
+ subcontrol-origin: padding;
+ subcontrol-position: right; /* position at the top right corner */
+ width: 24px;
+ height: 24px;
+ border-width: 3px;
+
+}
+
+QSpinBox::up-arrow
+{
+ image: url(icons:add.png);
+ width: 18px;
+ height: 18px;
+}
+
+
+QSpinBox::down-button
+{
+ subcontrol-origin: border;
+ subcontrol-position: left;
+ width: 24px;
+ height: 24px;
+ border-width: 3px;
+}
+
+QSpinBox::down-arrow
+{
+ image: url(icons:remove.png);
+ width: 18px;
+ height: 18px;
+}
+
+
+QScrollBar:horizontal
+{
+ border: 1px solid black;
+ background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0,0,139,60%), stop:1 rgba(173,216,230,60%) );
+ height: 15px;
+ margin: 0px 20px 0 20px;
+}
+
+QScrollBar::handle:horizontal
+{
+ border: 1px solid black;
+ background: rgba(0,0,139,60%);
+ min-width: 20px;
+}
+
+QScrollBar::add-line:horizontal
+{
+ border: 1px solid black;
+ background: rgba(0,0,139,60%);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::sub-line:horizontal
+{
+ border: 1px solid black;
+ background: rgba(0,0,139,60%);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+
+QScrollBar:left-arrow:horizontal, QScrollBar::right-arrow:horizontal
+{
+ border: none;
+ width: 16px;
+ height: 16px;
+}
+
+QScrollBar:left-arrow:horizontal
+{
+ image: url(icons:add.png)
+}
+
+QScrollBar::right-arrow:horizontal
+{
+ image: url(icons:remove.png)
+}
+
+QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
+{
+ background: none;
+}
+
diff --git a/demos/embedded/styledemo/files/blue.qss b/demos/embedded/styledemo/files/blue.qss
new file mode 100644
index 0000000..ac8671b
--- /dev/null
+++ b/demos/embedded/styledemo/files/blue.qss
@@ -0,0 +1,38 @@
+*
+{
+ color: beige;
+}
+
+QLabel, QAbstractButton
+{
+ font: bold;
+ color: yellow;
+}
+
+QFrame
+{
+ background-color: rgba(96,96,255,60%);
+ border-color: rgb(32,32,196);
+ border-width: 3px;
+ border-style: solid;
+ border-radius: 5;
+ padding: 3px;
+}
+
+QAbstractButton
+{
+ background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
+ stop:0 lightblue, stop:0.5 darkblue);
+ border-width: 3px;
+ border-color: darkblue;
+ border-style: solid;
+ border-radius: 5;
+ padding: 3px;
+}
+
+QAbstractButton:pressed
+{
+ background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
+ stop:0.5 darkblue, stop:1 lightblue);
+ border-color: beige;
+}
diff --git a/demos/embedded/styledemo/files/khaki.qss b/demos/embedded/styledemo/files/khaki.qss
new file mode 100644
index 0000000..b0d4a0f
--- /dev/null
+++ b/demos/embedded/styledemo/files/khaki.qss
@@ -0,0 +1,99 @@
+
+QWidget#StartScreen, QWidget#MainWidget {
+ border: none;
+}
+
+QWidget#StartScreen, .QFrame {
+ background-color: beige;
+}
+
+QPushButton, QToolButton {
+ background-color: palegoldenrod;
+ border-width: 2px;
+ border-color: darkkhaki;
+ border-style: solid;
+ border-radius: 5;
+ padding: 3px;
+ /* min-width: 96px; */
+ /* min-height: 48px; */
+}
+
+QPushButton:hover, QToolButton:hover {
+ background-color: khaki;
+}
+
+QPushButton:pressed, QToolButton:pressed {
+ padding-left: 5px;
+ padding-top: 5px;
+ background-color: #d0d67c;
+}
+
+QLabel, QAbstractButton {
+ font: italic "Times New Roman";
+}
+
+QFrame, QLabel#title {
+ border-width: 2px;
+ padding: 1px;
+ border-style: solid;
+ border-color: darkkhaki;
+ border-radius: 5px;
+}
+
+QFrame:focus {
+ border-width: 3px;
+ padding: 0px;
+}
+
+
+QLabel {
+ border: none;
+ padding: 0;
+ background: none;
+}
+
+QLabel#title {
+ font: 32px bold;
+}
+
+QSpinBox {
+ padding-left: 24px;
+ padding-right: 24px;
+ border-color: darkkhaki;
+ border-style: solid;
+ border-radius: 5;
+ border-width: 3;
+}
+
+QSpinBox::up-button
+{
+ subcontrol-origin: padding;
+ subcontrol-position: right; /* position at the top right corner */
+ width: 24px;
+ height: 24px;
+ border-width: 3px;
+ border-image: url(:/files/spindownpng) 1;
+}
+
+QSpinBox::up-arrow {
+ image: url(:/files/add.png);
+ width: 12px;
+ height: 12px;
+ }
+
+
+QSpinBox::down-button
+{
+ subcontrol-origin: border;
+ subcontrol-position: left;
+ width: 24px;
+ height: 24px;
+ border-width: 3px;
+ border-image: url(:/files/spindownpng) 1;
+}
+
+QSpinBox::down-arrow {
+ image: url(:/files/remove.png);
+ width: 12px;
+ height: 12px;
+ }
diff --git a/demos/embedded/styledemo/files/nature_1.jpg b/demos/embedded/styledemo/files/nature_1.jpg
new file mode 100644
index 0000000..3a04edb
--- /dev/null
+++ b/demos/embedded/styledemo/files/nature_1.jpg
Binary files differ
diff --git a/demos/embedded/styledemo/files/nostyle.qss b/demos/embedded/styledemo/files/nostyle.qss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/demos/embedded/styledemo/files/nostyle.qss
diff --git a/demos/embedded/styledemo/files/remove.png b/demos/embedded/styledemo/files/remove.png
new file mode 100755
index 0000000..a0ab1fa
--- /dev/null
+++ b/demos/embedded/styledemo/files/remove.png
Binary files differ
diff --git a/demos/embedded/styledemo/files/transparent.qss b/demos/embedded/styledemo/files/transparent.qss
new file mode 100644
index 0000000..b38eb36
--- /dev/null
+++ b/demos/embedded/styledemo/files/transparent.qss
@@ -0,0 +1,139 @@
+QWidget#StyleWidget
+{
+ background-color: none;
+ background-image: url(:/files/nature_1.jpg);
+}
+
+QLabel, QAbstractButton
+{
+ color: beige;
+}
+
+QFrame, QLabel#title {
+ border-width: 2px;
+ padding: 1px;
+ border-style: solid;
+ border-color: black;
+ border-radius: 5px;
+}
+
+QFrame:focus {
+ border-width: 3px;
+ padding: 0px;
+}
+
+
+
+QAbstractButton
+{
+ background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(173,216,230,60%), stop:1 rgba(0,0,139,60%) );
+ border-color: black;
+ border-style: solid;
+ border-width: 3px;
+ border-radius: 6px;
+}
+
+QAbstractButton:pressed, QAbstractButton:checked
+{
+ background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(0,0,139,60%), stop:1 rgba(173,216,230,60%) );
+}
+
+QSpinBox {
+ padding-left: 24px;
+ padding-right: 24px;
+ border-color: darkkhaki;
+ border-style: solid;
+ border-radius: 5;
+ border-width: 3;
+}
+
+QSpinBox::up-button
+{
+ subcontrol-origin: padding;
+ subcontrol-position: right; /* position at the top right corner */
+ width: 24px;
+ height: 24px;
+ border-width: 3px;
+
+}
+
+QSpinBox::up-arrow
+{
+ image: url(:/files/add.png);
+ width: 18px;
+ height: 18px;
+}
+
+
+QSpinBox::down-button
+{
+ subcontrol-origin: border;
+ subcontrol-position: left;
+ width: 24px;
+ height: 24px;
+ border-width: 3px;
+}
+
+QSpinBox::down-arrow
+{
+ image: url(:/files/remove.png);
+ width: 18px;
+ height: 18px;
+}
+
+
+QScrollBar:horizontal
+{
+ border: 1px solid black;
+ background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0,0,139,60%), stop:1 rgba(173,216,230,60%) );
+ height: 15px;
+ margin: 0px 20px 0 20px;
+}
+
+QScrollBar::handle:horizontal
+{
+ border: 1px solid black;
+ background: rgba(0,0,139,60%);
+ min-width: 20px;
+}
+
+QScrollBar::add-line:horizontal
+{
+ border: 1px solid black;
+ background: rgba(0,0,139,60%);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::sub-line:horizontal
+{
+ border: 1px solid black;
+ background: rgba(0,0,139,60%);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+
+QScrollBar:left-arrow:horizontal, QScrollBar::right-arrow:horizontal
+{
+ border: none;
+ width: 16px;
+ height: 16px;
+}
+
+QScrollBar:left-arrow:horizontal
+{
+ image: url(:/files/add.png)
+}
+
+QScrollBar::right-arrow:horizontal
+{
+ image: url(:/files/remove.png)
+}
+
+QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
+{
+ background: none;
+}
+
diff --git a/demos/embedded/styledemo/main.cpp b/demos/embedded/styledemo/main.cpp
new file mode 100644
index 0000000..6a7472e
--- /dev/null
+++ b/demos/embedded/styledemo/main.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QApplication>
+
+#include "stylewidget.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ Q_INIT_RESOURCE(styledemo);
+
+ app.setApplicationName("style");
+ app.setOrganizationName("Trolltech");
+ app.setOrganizationDomain("com.trolltech");
+
+ StyleWidget widget;
+ widget.showFullScreen();
+
+ return app.exec();
+}
+
diff --git a/demos/embedded/styledemo/styledemo.pro b/demos/embedded/styledemo/styledemo.pro
new file mode 100644
index 0000000..e0ef202
--- /dev/null
+++ b/demos/embedded/styledemo/styledemo.pro
@@ -0,0 +1,16 @@
+TEMPLATE = app
+
+# Input
+HEADERS += stylewidget.h
+FORMS += stylewidget.ui
+SOURCES += main.cpp stylewidget.cpp
+RESOURCES += styledemo.qrc
+
+target.path = $$[QT_INSTALL_DEMOS]/embedded/styledemo
+sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS *.pro *.html
+sources.path = $$[QT_INSTALL_DEMOS]/embedded/styledemo
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
+symbian:TARGET.UID3 = 0xA000A63F
diff --git a/demos/embedded/styledemo/styledemo.qrc b/demos/embedded/styledemo/styledemo.qrc
new file mode 100644
index 0000000..96237d4
--- /dev/null
+++ b/demos/embedded/styledemo/styledemo.qrc
@@ -0,0 +1,13 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>files/add.png</file>
+ <file>files/blue.qss</file>
+ <file>files/khaki.qss</file>
+ <file>files/nostyle.qss</file>
+ <file>files/transparent.qss</file>
+ <file>files/application.qss</file>
+ <file>files/nature_1.jpg</file>
+ <file>files/remove.png</file>
+</qresource>
+</RCC>
+
diff --git a/demos/embedded/styledemo/stylewidget.cpp b/demos/embedded/styledemo/stylewidget.cpp
new file mode 100644
index 0000000..304dd36
--- /dev/null
+++ b/demos/embedded/styledemo/stylewidget.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QApplication>
+#include <QString>
+#include <QFile>
+
+#include "stylewidget.h"
+
+
+
+StyleWidget::StyleWidget(QWidget *parent)
+ : QFrame(parent)
+{
+ m_ui.setupUi(this);
+}
+
+
+void StyleWidget::on_close_clicked()
+{
+ close();
+}
+
+void StyleWidget::on_blueStyle_clicked()
+{
+ QFile styleSheet(":/files/blue.qss");
+
+ if (!styleSheet.open(QIODevice::ReadOnly)) {
+ qWarning("Unable to open :/files/blue.qss");
+ return;
+ }
+
+ qApp->setStyleSheet(styleSheet.readAll());
+}
+
+void StyleWidget::on_khakiStyle_clicked()
+{
+ QFile styleSheet(":/files/khaki.qss");
+
+ if (!styleSheet.open(QIODevice::ReadOnly)) {
+ qWarning("Unable to open :/files/khaki.qss");
+ return;
+ }
+
+ qApp->setStyleSheet(styleSheet.readAll());
+}
+
+
+void StyleWidget::on_noStyle_clicked()
+{
+ QFile styleSheet(":/files/nostyle.qss");
+
+ if (!styleSheet.open(QIODevice::ReadOnly)) {
+ qWarning("Unable to open :/files/nostyle.qss");
+ return;
+ }
+
+ qApp->setStyleSheet(styleSheet.readAll());
+}
+
+
+void StyleWidget::on_transparentStyle_clicked()
+{
+ QFile styleSheet(":/files/transparent.qss");
+
+ if (!styleSheet.open(QIODevice::ReadOnly)) {
+ qWarning("Unable to open :/files/transparent.qss");
+ return;
+ }
+
+ qApp->setStyleSheet(styleSheet.readAll());
+}
+
+
+
diff --git a/demos/embedded/styledemo/stylewidget.h b/demos/embedded/styledemo/stylewidget.h
new file mode 100644
index 0000000..5ccb418
--- /dev/null
+++ b/demos/embedded/styledemo/stylewidget.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef STYLEWIDGET_H
+#define STYLEWIDGET_H
+
+#include <QFrame>
+
+#include "ui_stylewidget.h"
+
+class StyleWidget : public QFrame
+{
+ Q_OBJECT
+public:
+ StyleWidget(QWidget *parent = 0);
+
+private:
+ Ui_StyleWidget m_ui;
+
+private slots:
+ void on_close_clicked();
+ void on_blueStyle_clicked();
+ void on_khakiStyle_clicked();
+ void on_noStyle_clicked();
+ void on_transparentStyle_clicked();
+};
+
+#endif
diff --git a/demos/embedded/styledemo/stylewidget.ui b/demos/embedded/styledemo/stylewidget.ui
new file mode 100644
index 0000000..9c5f253
--- /dev/null
+++ b/demos/embedded/styledemo/stylewidget.ui
@@ -0,0 +1,435 @@
+<ui version="4.0" >
+ <class>StyleWidget</class>
+ <widget class="QWidget" name="StyleWidget" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>172</width>
+ <height>220</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <property name="spacing" >
+ <number>4</number>
+ </property>
+ <property name="margin" >
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Styles</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2" >
+ <property name="margin" >
+ <number>4</number>
+ </property>
+ <property name="spacing" >
+ <number>4</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QPushButton" name="transparentStyle" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="MinimumExpanding" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy" >
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ <property name="text" >
+ <string>Transp.</string>
+ </property>
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="checked" >
+ <bool>false</bool>
+ </property>
+ <property name="autoExclusive" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QPushButton" name="blueStyle" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="MinimumExpanding" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy" >
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ <property name="text" >
+ <string>Blue</string>
+ </property>
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="checked" >
+ <bool>false</bool>
+ </property>
+ <property name="autoExclusive" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QPushButton" name="khakiStyle" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="MinimumExpanding" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy" >
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ <property name="text" >
+ <string>Khaki</string>
+ </property>
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="checked" >
+ <bool>false</bool>
+ </property>
+ <property name="autoExclusive" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QPushButton" name="noStyle" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="MinimumExpanding" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy" >
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ <property name="text" >
+ <string>None</string>
+ </property>
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ <property name="autoExclusive" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_3" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QFrame" name="frame" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="MinimumExpanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="frameLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>My Value is:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="spinBox" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy" >
+ <enum>Qt::WheelFocus</enum>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="keyboardTracking" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout" >
+ <property name="spacing" >
+ <number>4</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QScrollBar" name="horizontalScrollBar" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>24</height>
+ </size>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QPushButton" name="pushButton_2" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy" >
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ <property name="text" >
+ <string>Show</string>
+ </property>
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ <property name="flat" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QScrollBar" name="horizontalScrollBar_2" >
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>24</height>
+ </size>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QPushButton" name="pushButton" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy" >
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ <property name="text" >
+ <string>Enable</string>
+ </property>
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ <property name="flat" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="close" >
+ <property name="focusPolicy" >
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ <property name="text" >
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="StyleDemo.qrc" />
+ </resources>
+ <connections>
+ <connection>
+ <sender>horizontalScrollBar</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>horizontalScrollBar_2</receiver>
+ <slot>setValue(int)</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>134</x>
+ <y>196</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>523</x>
+ <y>193</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>horizontalScrollBar_2</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>horizontalScrollBar</receiver>
+ <slot>setValue(int)</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>577</x>
+ <y>199</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>127</x>
+ <y>207</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>pushButton</sender>
+ <signal>clicked(bool)</signal>
+ <receiver>horizontalScrollBar_2</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>566</x>
+ <y>241</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>492</x>
+ <y>207</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>pushButton_2</sender>
+ <signal>clicked(bool)</signal>
+ <receiver>horizontalScrollBar</receiver>
+ <slot>setVisible(bool)</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>123</x>
+ <y>239</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>123</x>
+ <y>184</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>spinBox</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>horizontalScrollBar_2</receiver>
+ <slot>setValue(int)</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>603</x>
+ <y>136</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>575</x>
+ <y>199</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/demos/embeddeddialogs/No-Ones-Laughing-3.jpg b/demos/embeddeddialogs/No-Ones-Laughing-3.jpg
new file mode 100644
index 0000000..445567f
--- /dev/null
+++ b/demos/embeddeddialogs/No-Ones-Laughing-3.jpg
Binary files differ
diff --git a/demos/embeddeddialogs/customproxy.cpp b/demos/embeddeddialogs/customproxy.cpp
new file mode 100644
index 0000000..56a0548
--- /dev/null
+++ b/demos/embeddeddialogs/customproxy.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "customproxy.h"
+
+#include <QtGui>
+
+CustomProxy::CustomProxy(QGraphicsItem *parent, Qt::WindowFlags wFlags)
+ : QGraphicsProxyWidget(parent, wFlags), popupShown(false)
+{
+ timeLine = new QTimeLine(250, this);
+ connect(timeLine, SIGNAL(valueChanged(qreal)),
+ this, SLOT(updateStep(qreal)));
+ connect(timeLine, SIGNAL(stateChanged(QTimeLine::State)),
+ this, SLOT(stateChanged(QTimeLine::State)));
+}
+
+QRectF CustomProxy::boundingRect() const
+{
+ return QGraphicsProxyWidget::boundingRect().adjusted(0, 0, 10, 10);
+}
+
+void CustomProxy::paintWindowFrame(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
+{
+ const QColor color(0, 0, 0, 64);
+
+ QRectF r = windowFrameRect();
+ QRectF right(r.right(), r.top() + 10, 10, r.height() - 10);
+ QRectF bottom(r.left() + 10, r.bottom(), r.width(), 10);
+ bool intersectsRight = right.intersects(option->exposedRect);
+ bool intersectsBottom = bottom.intersects(option->exposedRect);
+ if (intersectsRight && intersectsBottom) {
+ QPainterPath path;
+ path.addRect(right);
+ path.addRect(bottom);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(color);
+ painter->drawPath(path);
+ } else if (intersectsBottom) {
+ painter->fillRect(bottom, color);
+ } else if (intersectsRight) {
+ painter->fillRect(right, color);
+ }
+
+ QGraphicsProxyWidget::paintWindowFrame(painter, option, widget);
+}
+
+void CustomProxy::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+ QGraphicsProxyWidget::hoverEnterEvent(event);
+ scene()->setActiveWindow(this);
+ if (timeLine->currentValue() != 1)
+ zoomIn();
+}
+
+void CustomProxy::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ QGraphicsProxyWidget::hoverLeaveEvent(event);
+ if (!popupShown && (timeLine->direction() != QTimeLine::Backward || timeLine->currentValue() != 0))
+ zoomOut();
+}
+
+bool CustomProxy::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
+{
+ if (watched->isWindow() && (event->type() == QEvent::UngrabMouse || event->type() == QEvent::GrabMouse)) {
+ popupShown = watched->isVisible();
+ if (!popupShown && !isUnderMouse())
+ zoomOut();
+ }
+ return QGraphicsProxyWidget::sceneEventFilter(watched, event);
+}
+
+QVariant CustomProxy::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ if (change == ItemChildRemovedChange)
+ removeSceneEventFilter(this);
+ return QGraphicsProxyWidget::itemChange(change, value);
+}
+
+void CustomProxy::updateStep(qreal step)
+{
+ QRectF r = boundingRect();
+ setTransform(QTransform()
+ .translate(r.width() / 2, r.height() / 2)
+ .rotate(step * 30, Qt::XAxis)
+ .rotate(step * 10, Qt::YAxis)
+ .rotate(step * 5, Qt::ZAxis)
+ .scale(1 + 1.5 * step, 1 + 1.5 * step)
+ .translate(-r.width() / 2, -r.height() / 2));
+}
+
+void CustomProxy::stateChanged(QTimeLine::State state)
+{
+ if (state == QTimeLine::Running) {
+ if (timeLine->direction() == QTimeLine::Forward)
+ setCacheMode(ItemCoordinateCache);
+ } else if (state == QTimeLine::NotRunning) {
+ if (timeLine->direction() == QTimeLine::Backward)
+ setCacheMode(DeviceCoordinateCache);
+ }
+}
+
+void CustomProxy::zoomIn()
+{
+ if (timeLine->direction() != QTimeLine::Forward)
+ timeLine->setDirection(QTimeLine::Forward);
+ if (timeLine->state() == QTimeLine::NotRunning)
+ timeLine->start();
+}
+
+void CustomProxy::zoomOut()
+{
+ if (timeLine->direction() != QTimeLine::Backward)
+ timeLine->setDirection(QTimeLine::Backward);
+ if (timeLine->state() == QTimeLine::NotRunning)
+ timeLine->start();
+}
diff --git a/demos/embeddeddialogs/customproxy.h b/demos/embeddeddialogs/customproxy.h
new file mode 100644
index 0000000..0a5fbaf
--- /dev/null
+++ b/demos/embeddeddialogs/customproxy.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CUSTOMPROXY_H
+#define CUSTOMPROXY_H
+
+#include <QtCore/qtimeline.h>
+#include <QtGui/qgraphicsproxywidget.h>
+
+class CustomProxy : public QGraphicsProxyWidget
+{
+ Q_OBJECT
+public:
+ CustomProxy(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0);
+
+ QRectF boundingRect() const;
+ void paintWindowFrame(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget);
+
+protected:
+ void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ bool sceneEventFilter(QGraphicsItem *watched, QEvent *event);
+ QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+
+private slots:
+ void updateStep(qreal step);
+ void stateChanged(QTimeLine::State);
+ void zoomIn();
+ void zoomOut();
+
+private:
+ QTimeLine *timeLine;
+ bool popupShown;
+};
+
+#endif
diff --git a/demos/embeddeddialogs/embeddeddialog.cpp b/demos/embeddeddialogs/embeddeddialog.cpp
new file mode 100644
index 0000000..40f361c
--- /dev/null
+++ b/demos/embeddeddialogs/embeddeddialog.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "embeddeddialog.h"
+#include "ui_embeddeddialog.h"
+
+#include <QtGui>
+
+EmbeddedDialog::EmbeddedDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ ui = new Ui_embeddedDialog;
+ ui->setupUi(this);
+ ui->layoutDirection->setCurrentIndex(layoutDirection() != Qt::LeftToRight);
+
+ foreach (QString styleName, QStyleFactory::keys()) {
+ ui->style->addItem(styleName);
+ if (style()->objectName().toLower() == styleName.toLower())
+ ui->style->setCurrentIndex(ui->style->count() - 1);
+ }
+
+ connect(ui->layoutDirection, SIGNAL(activated(int)),
+ this, SLOT(layoutDirectionChanged(int)));
+ connect(ui->spacing, SIGNAL(valueChanged(int)),
+ this, SLOT(spacingChanged(int)));
+ connect(ui->fontComboBox, SIGNAL(currentFontChanged(const QFont &)),
+ this, SLOT(fontChanged(const QFont &)));
+ connect(ui->style, SIGNAL(activated(QString)),
+ this, SLOT(styleChanged(QString)));
+}
+
+EmbeddedDialog::~EmbeddedDialog()
+{
+ delete ui;
+}
+
+void EmbeddedDialog::layoutDirectionChanged(int index)
+{
+ setLayoutDirection(index == 0 ? Qt::LeftToRight : Qt::RightToLeft);
+}
+
+void EmbeddedDialog::spacingChanged(int spacing)
+{
+ layout()->setSpacing(spacing);
+ adjustSize();
+}
+
+void EmbeddedDialog::fontChanged(const QFont &font)
+{
+ setFont(font);
+}
+
+static void setStyleHelper(QWidget *widget, QStyle *style)
+{
+ widget->setStyle(style);
+ widget->setPalette(style->standardPalette());
+ foreach (QObject *child, widget->children()) {
+ if (QWidget *childWidget = qobject_cast<QWidget *>(child))
+ setStyleHelper(childWidget, style);
+ }
+}
+
+void EmbeddedDialog::styleChanged(const QString &styleName)
+{
+ QStyle *style = QStyleFactory::create(styleName);
+ if (style)
+ setStyleHelper(this, style);
+}
diff --git a/demos/embeddeddialogs/embeddeddialog.h b/demos/embeddeddialogs/embeddeddialog.h
new file mode 100644
index 0000000..787196c
--- /dev/null
+++ b/demos/embeddeddialogs/embeddeddialog.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef EMBEDDEDDIALOG_H
+#define EMBEDDEDDIALOG_H
+
+#include <QtGui/qdialog.h>
+
+QT_FORWARD_DECLARE_CLASS(Ui_embeddedDialog);
+
+class EmbeddedDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ EmbeddedDialog(QWidget *parent = 0);
+ ~EmbeddedDialog();
+
+private slots:
+ void layoutDirectionChanged(int index);
+ void spacingChanged(int spacing);
+ void fontChanged(const QFont &font);
+ void styleChanged(const QString &styleName);
+
+private:
+ Ui_embeddedDialog *ui;
+};
+
+#endif
diff --git a/demos/embeddeddialogs/embeddeddialog.ui b/demos/embeddeddialogs/embeddeddialog.ui
new file mode 100644
index 0000000..f967b10
--- /dev/null
+++ b/demos/embeddeddialogs/embeddeddialog.ui
@@ -0,0 +1,87 @@
+<ui version="4.0" >
+ <class>embeddedDialog</class>
+ <widget class="QDialog" name="embeddedDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>407</width>
+ <height>134</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Embedded Dialog</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Layout Direction:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>layoutDirection</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="layoutDirection" >
+ <item>
+ <property name="text" >
+ <string>Left to Right</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Right to Left</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Select Font:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>fontComboBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QFontComboBox" name="fontComboBox" />
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Style:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>style</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QComboBox" name="style" />
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_4" >
+ <property name="text" >
+ <string>Layout spacing:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>spacing</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QSlider" name="spacing" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/demos/embeddeddialogs/embeddeddialogs.pro b/demos/embeddeddialogs/embeddeddialogs.pro
new file mode 100644
index 0000000..d9948a9
--- /dev/null
+++ b/demos/embeddeddialogs/embeddeddialogs.pro
@@ -0,0 +1,19 @@
+SOURCES += main.cpp
+SOURCES += customproxy.cpp embeddeddialog.cpp
+HEADERS += customproxy.h embeddeddialog.h
+
+FORMS += embeddeddialog.ui
+RESOURCES += embeddeddialogs.qrc
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/embeddeddialogs
+sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS *.png *.jpg *.plist *.icns *.ico *.rc *.pro *.html *.doc images
+sources.path = $$[QT_INSTALL_DEMOS]/embeddeddialogs
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
diff --git a/demos/embeddeddialogs/embeddeddialogs.qrc b/demos/embeddeddialogs/embeddeddialogs.qrc
new file mode 100644
index 0000000..33be503
--- /dev/null
+++ b/demos/embeddeddialogs/embeddeddialogs.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource>
+ <file>No-Ones-Laughing-3.jpg</file>
+ </qresource>
+</RCC>
diff --git a/demos/embeddeddialogs/main.cpp b/demos/embeddeddialogs/main.cpp
new file mode 100644
index 0000000..4cf7325
--- /dev/null
+++ b/demos/embeddeddialogs/main.cpp
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "customproxy.h"
+#include "embeddeddialog.h"
+
+#include <QtGui>
+
+int main(int argc, char *argv[])
+{
+ Q_INIT_RESOURCE(embeddeddialogs);
+ QApplication app(argc, argv);
+
+ QGraphicsScene scene;
+ scene.setStickyFocus(true);
+#ifndef Q_OS_WINCE
+ const int gridSize = 10;
+#else
+ const int gridSize = 5;
+#endif
+
+ for (int y = 0; y < gridSize; ++y) {
+ for (int x = 0; x < gridSize; ++x) {
+ CustomProxy *proxy = new CustomProxy(0, Qt::Window);
+ proxy->setWidget(new EmbeddedDialog);
+
+ QRectF rect = proxy->boundingRect();
+
+ proxy->setPos(x * rect.width() * 1.05, y * rect.height() * 1.05);
+ proxy->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+
+ scene.addItem(proxy);
+ proxy->installSceneEventFilter(proxy);
+ }
+ }
+ scene.setSceneRect(scene.itemsBoundingRect());
+
+ QGraphicsView view(&scene);
+ view.scale(0.5, 0.5);
+ view.setRenderHints(view.renderHints() | QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ view.setBackgroundBrush(QPixmap(":/No-Ones-Laughing-3.jpg"));
+ view.setCacheMode(QGraphicsView::CacheBackground);
+ view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
+ view.show();
+ view.setWindowTitle("Embedded Dialogs Demo");
+ return app.exec();
+}
diff --git a/demos/gradients/gradients.cpp b/demos/gradients/gradients.cpp
new file mode 100644
index 0000000..6256ba9
--- /dev/null
+++ b/demos/gradients/gradients.cpp
@@ -0,0 +1,516 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gradients.h"
+#include "hoverpoints.h"
+
+ShadeWidget::ShadeWidget(ShadeType type, QWidget *parent)
+ : QWidget(parent), m_shade_type(type), m_alpha_gradient(QLinearGradient(0, 0, 0, 0))
+{
+
+ // Checkers background
+ if (m_shade_type == ARGBShade) {
+ QPixmap pm(20, 20);
+ QPainter pmp(&pm);
+ pmp.fillRect(0, 0, 10, 10, Qt::lightGray);
+ pmp.fillRect(10, 10, 10, 10, Qt::lightGray);
+ pmp.fillRect(0, 10, 10, 10, Qt::darkGray);
+ pmp.fillRect(10, 0, 10, 10, Qt::darkGray);
+ pmp.end();
+ QPalette pal = palette();
+ pal.setBrush(backgroundRole(), QBrush(pm));
+ setAutoFillBackground(true);
+ setPalette(pal);
+
+ } else {
+ setAttribute(Qt::WA_NoBackground);
+
+ }
+
+ QPolygonF points;
+ points << QPointF(0, sizeHint().height())
+ << QPointF(sizeHint().width(), 0);
+
+ m_hoverPoints = new HoverPoints(this, HoverPoints::CircleShape);
+// m_hoverPoints->setConnectionType(HoverPoints::LineConnection);
+ m_hoverPoints->setPoints(points);
+ m_hoverPoints->setPointLock(0, HoverPoints::LockToLeft);
+ m_hoverPoints->setPointLock(1, HoverPoints::LockToRight);
+ m_hoverPoints->setSortType(HoverPoints::XSort);
+
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ connect(m_hoverPoints, SIGNAL(pointsChanged(const QPolygonF &)), this, SIGNAL(colorsChanged()));
+}
+
+
+QPolygonF ShadeWidget::points() const
+{
+ return m_hoverPoints->points();
+}
+
+
+uint ShadeWidget::colorAt(int x)
+{
+ generateShade();
+
+ QPolygonF pts = m_hoverPoints->points();
+ for (int i=1; i < pts.size(); ++i) {
+ if (pts.at(i-1).x() <= x && pts.at(i).x() >= x) {
+ QLineF l(pts.at(i-1), pts.at(i));
+ l.setLength(l.length() * ((x - l.x1()) / l.dx()));
+ return m_shade.pixel(qRound(qMin(l.x2(), (qreal(m_shade.width() - 1)))),
+ qRound(qMin(l.y2(), qreal(m_shade.height() - 1))));
+ }
+ }
+ return 0;
+}
+
+
+void ShadeWidget::setGradientStops(const QGradientStops &stops)
+{
+ if (m_shade_type == ARGBShade) {
+ m_alpha_gradient = QLinearGradient(0, 0, width(), 0);
+
+ for (int i=0; i<stops.size(); ++i) {
+ QColor c = stops.at(i).second;
+ m_alpha_gradient.setColorAt(stops.at(i).first, QColor(c.red(), c.green(), c.blue()));
+ }
+
+ m_shade = QImage();
+ generateShade();
+ update();
+ }
+}
+
+
+void ShadeWidget::paintEvent(QPaintEvent *)
+{
+ generateShade();
+
+ QPainter p(this);
+ p.drawImage(0, 0, m_shade);
+
+ p.setPen(QColor(146, 146, 146));
+ p.drawRect(0, 0, width() - 1, height() - 1);
+}
+
+
+void ShadeWidget::generateShade()
+{
+ if (m_shade.isNull() || m_shade.size() != size()) {
+
+ if (m_shade_type == ARGBShade) {
+ m_shade = QImage(size(), QImage::Format_ARGB32_Premultiplied);
+ m_shade.fill(0);
+
+ QPainter p(&m_shade);
+ p.fillRect(rect(), m_alpha_gradient);
+
+ p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+ QLinearGradient fade(0, 0, 0, height());
+ fade.setColorAt(0, QColor(0, 0, 0, 255));
+ fade.setColorAt(1, QColor(0, 0, 0, 0));
+ p.fillRect(rect(), fade);
+
+ } else {
+ m_shade = QImage(size(), QImage::Format_RGB32);
+ QLinearGradient shade(0, 0, 0, height());
+ shade.setColorAt(1, Qt::black);
+
+ if (m_shade_type == RedShade)
+ shade.setColorAt(0, Qt::red);
+ else if (m_shade_type == GreenShade)
+ shade.setColorAt(0, Qt::green);
+ else
+ shade.setColorAt(0, Qt::blue);
+
+ QPainter p(&m_shade);
+ p.fillRect(rect(), shade);
+ }
+ }
+
+
+}
+
+
+GradientEditor::GradientEditor(QWidget *parent)
+ : QWidget(parent)
+{
+ QVBoxLayout *vbox = new QVBoxLayout(this);
+ vbox->setSpacing(1);
+ vbox->setMargin(1);
+
+ m_red_shade = new ShadeWidget(ShadeWidget::RedShade, this);
+ m_green_shade = new ShadeWidget(ShadeWidget::GreenShade, this);
+ m_blue_shade = new ShadeWidget(ShadeWidget::BlueShade, this);
+ m_alpha_shade = new ShadeWidget(ShadeWidget::ARGBShade, this);
+
+ vbox->addWidget(m_red_shade);
+ vbox->addWidget(m_green_shade);
+ vbox->addWidget(m_blue_shade);
+ vbox->addWidget(m_alpha_shade);
+
+ connect(m_red_shade, SIGNAL(colorsChanged()), this, SLOT(pointsUpdated()));
+ connect(m_green_shade, SIGNAL(colorsChanged()), this, SLOT(pointsUpdated()));
+ connect(m_blue_shade, SIGNAL(colorsChanged()), this, SLOT(pointsUpdated()));
+ connect(m_alpha_shade, SIGNAL(colorsChanged()), this, SLOT(pointsUpdated()));
+}
+
+
+inline static bool x_less_than(const QPointF &p1, const QPointF &p2)
+{
+ return p1.x() < p2.x();
+}
+
+
+void GradientEditor::pointsUpdated()
+{
+ qreal w = m_alpha_shade->width();
+
+ QGradientStops stops;
+
+ QPolygonF points;
+
+ points += m_red_shade->points();
+ points += m_green_shade->points();
+ points += m_blue_shade->points();
+ points += m_alpha_shade->points();
+
+ qSort(points.begin(), points.end(), x_less_than);
+
+ for (int i=0; i<points.size(); ++i) {
+ qreal x = int(points.at(i).x());
+ if (i < points.size() - 1 && x == points.at(i+1).x())
+ continue;
+ QColor color((0x00ff0000 & m_red_shade->colorAt(int(x))) >> 16,
+ (0x0000ff00 & m_green_shade->colorAt(int(x))) >> 8,
+ (0x000000ff & m_blue_shade->colorAt(int(x))),
+ (0xff000000 & m_alpha_shade->colorAt(int(x))) >> 24);
+
+ if (x / w > 1)
+ return;
+
+ stops << QGradientStop(x / w, color);
+ }
+
+ m_alpha_shade->setGradientStops(stops);
+
+ emit gradientStopsChanged(stops);
+}
+
+
+static void set_shade_points(const QPolygonF &points, ShadeWidget *shade)
+{
+ shade->hoverPoints()->setPoints(points);
+ shade->hoverPoints()->setPointLock(0, HoverPoints::LockToLeft);
+ shade->hoverPoints()->setPointLock(points.size() - 1, HoverPoints::LockToRight);
+ shade->update();
+}
+
+void GradientEditor::setGradientStops(const QGradientStops &stops)
+{
+ QPolygonF pts_red, pts_green, pts_blue, pts_alpha;
+
+ qreal h_red = m_red_shade->height();
+ qreal h_green = m_green_shade->height();
+ qreal h_blue = m_blue_shade->height();
+ qreal h_alpha = m_alpha_shade->height();
+
+ for (int i=0; i<stops.size(); ++i) {
+ qreal pos = stops.at(i).first;
+ QRgb color = stops.at(i).second.rgba();
+ pts_red << QPointF(pos * m_red_shade->width(), h_red - qRed(color) * h_red / 255);
+ pts_green << QPointF(pos * m_green_shade->width(), h_green - qGreen(color) * h_green / 255);
+ pts_blue << QPointF(pos * m_blue_shade->width(), h_blue - qBlue(color) * h_blue / 255);
+ pts_alpha << QPointF(pos * m_alpha_shade->width(), h_alpha - qAlpha(color) * h_alpha / 255);
+ }
+
+ set_shade_points(pts_red, m_red_shade);
+ set_shade_points(pts_green, m_green_shade);
+ set_shade_points(pts_blue, m_blue_shade);
+ set_shade_points(pts_alpha, m_alpha_shade);
+
+}
+
+GradientWidget::GradientWidget(QWidget *parent)
+ : QWidget(parent)
+{
+ setWindowTitle(tr("Gradients"));
+
+ m_renderer = new GradientRenderer(this);
+
+ QGroupBox *mainGroup = new QGroupBox(this);
+ mainGroup->setTitle(tr("Gradients"));
+
+ QGroupBox *editorGroup = new QGroupBox(mainGroup);
+ editorGroup->setTitle(tr("Color Editor"));
+ m_editor = new GradientEditor(editorGroup);
+
+ QGroupBox *typeGroup = new QGroupBox(mainGroup);
+ typeGroup->setTitle(tr("Gradient Type"));
+ m_linearButton = new QRadioButton(tr("Linear Gradient"), typeGroup);
+ m_radialButton = new QRadioButton(tr("Radial Gradient"), typeGroup);
+ m_conicalButton = new QRadioButton(tr("Conical Gradient"), typeGroup);
+
+ QGroupBox *spreadGroup = new QGroupBox(mainGroup);
+ spreadGroup->setTitle(tr("Spread Method"));
+ m_padSpreadButton = new QRadioButton(tr("Pad Spread"), spreadGroup);
+ m_reflectSpreadButton = new QRadioButton(tr("Reflect Spread"), spreadGroup);
+ m_repeatSpreadButton = new QRadioButton(tr("Repeat Spread"), spreadGroup);
+
+ QGroupBox *defaultsGroup = new QGroupBox(mainGroup);
+ defaultsGroup->setTitle(tr("Defaults"));
+ QPushButton *default1Button = new QPushButton(tr("1"), defaultsGroup);
+ QPushButton *default2Button = new QPushButton(tr("2"), defaultsGroup);
+ QPushButton *default3Button = new QPushButton(tr("3"), defaultsGroup);
+ QPushButton *default4Button = new QPushButton(tr("Reset"), editorGroup);
+
+ QPushButton *showSourceButton = new QPushButton(mainGroup);
+ showSourceButton->setText(tr("Show Source"));
+#ifdef QT_OPENGL_SUPPORT
+ QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
+ enableOpenGLButton->setText(tr("Use OpenGL"));
+ enableOpenGLButton->setCheckable(true);
+ enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
+ if (!QGLFormat::hasOpenGL())
+ enableOpenGLButton->hide();
+#endif
+ QPushButton *whatsThisButton = new QPushButton(mainGroup);
+ whatsThisButton->setText(tr("What's This?"));
+ whatsThisButton->setCheckable(true);
+
+ // Layouts
+ QHBoxLayout *mainLayout = new QHBoxLayout(this);
+ mainLayout->addWidget(m_renderer);
+ mainLayout->addWidget(mainGroup);
+
+ mainGroup->setFixedWidth(180);
+ QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
+ mainGroupLayout->addWidget(editorGroup);
+ mainGroupLayout->addWidget(typeGroup);
+ mainGroupLayout->addWidget(spreadGroup);
+ mainGroupLayout->addWidget(defaultsGroup);
+ mainGroupLayout->addStretch(1);
+ mainGroupLayout->addWidget(showSourceButton);
+#ifdef QT_OPENGL_SUPPORT
+ mainGroupLayout->addWidget(enableOpenGLButton);
+#endif
+ mainGroupLayout->addWidget(whatsThisButton);
+
+ QVBoxLayout *editorGroupLayout = new QVBoxLayout(editorGroup);
+ editorGroupLayout->addWidget(m_editor);
+
+ QVBoxLayout *typeGroupLayout = new QVBoxLayout(typeGroup);
+ typeGroupLayout->addWidget(m_linearButton);
+ typeGroupLayout->addWidget(m_radialButton);
+ typeGroupLayout->addWidget(m_conicalButton);
+
+ QVBoxLayout *spreadGroupLayout = new QVBoxLayout(spreadGroup);
+ spreadGroupLayout->addWidget(m_padSpreadButton);
+ spreadGroupLayout->addWidget(m_repeatSpreadButton);
+ spreadGroupLayout->addWidget(m_reflectSpreadButton);
+
+ QHBoxLayout *defaultsGroupLayout = new QHBoxLayout(defaultsGroup);
+ defaultsGroupLayout->addWidget(default1Button);
+ defaultsGroupLayout->addWidget(default2Button);
+ defaultsGroupLayout->addWidget(default3Button);
+ editorGroupLayout->addWidget(default4Button);
+
+ connect(m_editor, SIGNAL(gradientStopsChanged(const QGradientStops &)),
+ m_renderer, SLOT(setGradientStops(const QGradientStops &)));
+
+ connect(m_linearButton, SIGNAL(clicked()), m_renderer, SLOT(setLinearGradient()));
+ connect(m_radialButton, SIGNAL(clicked()), m_renderer, SLOT(setRadialGradient()));
+ connect(m_conicalButton, SIGNAL(clicked()), m_renderer, SLOT(setConicalGradient()));
+
+ connect(m_padSpreadButton, SIGNAL(clicked()), m_renderer, SLOT(setPadSpread()));
+ connect(m_reflectSpreadButton, SIGNAL(clicked()), m_renderer, SLOT(setReflectSpread()));
+ connect(m_repeatSpreadButton, SIGNAL(clicked()), m_renderer, SLOT(setRepeatSpread()));
+
+ connect(default1Button, SIGNAL(clicked()), this, SLOT(setDefault1()));
+ connect(default2Button, SIGNAL(clicked()), this, SLOT(setDefault2()));
+ connect(default3Button, SIGNAL(clicked()), this, SLOT(setDefault3()));
+ connect(default4Button, SIGNAL(clicked()), this, SLOT(setDefault4()));
+
+ connect(showSourceButton, SIGNAL(clicked()), m_renderer, SLOT(showSource()));
+#ifdef QT_OPENGL_SUPPORT
+ connect(enableOpenGLButton, SIGNAL(clicked(bool)), m_renderer, SLOT(enableOpenGL(bool)));
+#endif
+ connect(whatsThisButton, SIGNAL(clicked(bool)), m_renderer, SLOT(setDescriptionEnabled(bool)));
+ connect(whatsThisButton, SIGNAL(clicked(bool)),
+ m_renderer->hoverPoints(), SLOT(setDisabled(bool)));
+ connect(m_renderer, SIGNAL(descriptionEnabledChanged(bool)),
+ whatsThisButton, SLOT(setChecked(bool)));
+ connect(m_renderer, SIGNAL(descriptionEnabledChanged(bool)),
+ m_renderer->hoverPoints(), SLOT(setDisabled(bool)));
+
+ m_renderer->loadSourceFile(":res/gradients/gradients.cpp");
+ m_renderer->loadDescription(":res/gradients/gradients.html");
+
+ QTimer::singleShot(50, this, SLOT(setDefault1()));
+}
+
+void GradientWidget::setDefault(int config)
+{
+ QGradientStops stops;
+ QPolygonF points;
+ switch (config) {
+ case 1:
+ stops << QGradientStop(0.00, QColor::fromRgba(0));
+ stops << QGradientStop(0.04, QColor::fromRgba(0xff131360));
+ stops << QGradientStop(0.08, QColor::fromRgba(0xff202ccc));
+ stops << QGradientStop(0.42, QColor::fromRgba(0xff93d3f9));
+ stops << QGradientStop(0.51, QColor::fromRgba(0xffb3e6ff));
+ stops << QGradientStop(0.73, QColor::fromRgba(0xffffffec));
+ stops << QGradientStop(0.92, QColor::fromRgba(0xff5353d9));
+ stops << QGradientStop(0.96, QColor::fromRgba(0xff262666));
+ stops << QGradientStop(1.00, QColor::fromRgba(0));
+ m_linearButton->animateClick();
+ m_repeatSpreadButton->animateClick();
+ break;
+
+ case 2:
+ stops << QGradientStop(0.00, QColor::fromRgba(0xffffffff));
+ stops << QGradientStop(0.11, QColor::fromRgba(0xfff9ffa0));
+ stops << QGradientStop(0.13, QColor::fromRgba(0xfff9ff99));
+ stops << QGradientStop(0.14, QColor::fromRgba(0xfff3ff86));
+ stops << QGradientStop(0.49, QColor::fromRgba(0xff93b353));
+ stops << QGradientStop(0.87, QColor::fromRgba(0xff264619));
+ stops << QGradientStop(0.96, QColor::fromRgba(0xff0c1306));
+ stops << QGradientStop(1.00, QColor::fromRgba(0));
+ m_radialButton->animateClick();
+ m_padSpreadButton->animateClick();
+ break;
+
+ case 3:
+ stops << QGradientStop(0.00, QColor::fromRgba(0));
+ stops << QGradientStop(0.10, QColor::fromRgba(0xffe0cc73));
+ stops << QGradientStop(0.17, QColor::fromRgba(0xffc6a006));
+ stops << QGradientStop(0.46, QColor::fromRgba(0xff600659));
+ stops << QGradientStop(0.72, QColor::fromRgba(0xff0680ac));
+ stops << QGradientStop(0.92, QColor::fromRgba(0xffb9d9e6));
+ stops << QGradientStop(1.00, QColor::fromRgba(0));
+ m_conicalButton->animateClick();
+ m_padSpreadButton->animateClick();
+ break;
+
+ case 4:
+ stops << QGradientStop(0.00, QColor::fromRgba(0xff000000));
+ stops << QGradientStop(1.00, QColor::fromRgba(0xffffffff));
+ break;
+
+ default:
+ qWarning("bad default: %d\n", config);
+ break;
+ }
+
+ QPolygonF pts;
+ int h_off = m_renderer->width() / 10;
+ int v_off = m_renderer->height() / 8;
+ pts << QPointF(m_renderer->width() / 2, m_renderer->height() / 2)
+ << QPointF(m_renderer->width() / 2 - h_off, m_renderer->height() / 2 - v_off);
+
+ m_editor->setGradientStops(stops);
+ m_renderer->hoverPoints()->setPoints(pts);
+ m_renderer->setGradientStops(stops);
+}
+
+
+GradientRenderer::GradientRenderer(QWidget *parent)
+ : ArthurFrame(parent)
+{
+ m_hoverPoints = new HoverPoints(this, HoverPoints::CircleShape);
+ m_hoverPoints->setPointSize(QSize(20, 20));
+ m_hoverPoints->setConnectionType(HoverPoints::NoConnection);
+ m_hoverPoints->setEditable(false);
+
+ QVector<QPointF> points;
+ points << QPointF(100, 100) << QPointF(200, 200);
+ m_hoverPoints->setPoints(points);
+
+ m_spread = QGradient::PadSpread;
+ m_gradientType = Qt::LinearGradientPattern;
+}
+
+void GradientRenderer::setGradientStops(const QGradientStops &stops)
+{
+ m_stops = stops;
+ update();
+}
+
+
+void GradientRenderer::mousePressEvent(QMouseEvent *)
+{
+ setDescriptionEnabled(false);
+}
+
+void GradientRenderer::paint(QPainter *p)
+{
+ QPolygonF pts = m_hoverPoints->points();
+
+ QGradient g;
+
+ if (m_gradientType == Qt::LinearGradientPattern) {
+ g = QLinearGradient(pts.at(0), pts.at(1));
+
+ } else if (m_gradientType == Qt::RadialGradientPattern) {
+ g = QRadialGradient(pts.at(0), qMin(width(), height()) / 3.0, pts.at(1));
+
+ } else {
+ QLineF l(pts.at(0), pts.at(1));
+ qreal angle = l.angle(QLineF(0, 0, 1, 0));
+ if (l.dy() > 0)
+ angle = 360 - angle;
+ g = QConicalGradient(pts.at(0), angle);
+ }
+
+ for (int i=0; i<m_stops.size(); ++i)
+ g.setColorAt(m_stops.at(i).first, m_stops.at(i).second);
+
+ g.setSpread(m_spread);
+
+ p->setBrush(g);
+ p->setPen(Qt::NoPen);
+
+ p->drawRect(rect());
+
+}
diff --git a/demos/gradients/gradients.h b/demos/gradients/gradients.h
new file mode 100644
index 0000000..74e8417
--- /dev/null
+++ b/demos/gradients/gradients.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GRADIENTS_H
+#define GRADIENTS_H
+
+#include "arthurwidgets.h"
+
+#include <QtGui>
+
+class HoverPoints;
+
+
+class ShadeWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ enum ShadeType {
+ RedShade,
+ GreenShade,
+ BlueShade,
+ ARGBShade
+ };
+
+ ShadeWidget(ShadeType type, QWidget *parent);
+
+ void setGradientStops(const QGradientStops &stops);
+
+ void paintEvent(QPaintEvent *e);
+
+ QSize sizeHint() const { return QSize(150, 40); }
+ QPolygonF points() const;
+
+ HoverPoints *hoverPoints() const { return m_hoverPoints; }
+
+ uint colorAt(int x);
+
+signals:
+ void colorsChanged();
+
+private:
+ void generateShade();
+
+ ShadeType m_shade_type;
+ QImage m_shade;
+ HoverPoints *m_hoverPoints;
+ QLinearGradient m_alpha_gradient;
+};
+
+class GradientEditor : public QWidget
+{
+ Q_OBJECT
+public:
+ GradientEditor(QWidget *parent);
+
+ void setGradientStops(const QGradientStops &stops);
+
+public slots:
+ void pointsUpdated();
+
+signals:
+ void gradientStopsChanged(const QGradientStops &stops);
+
+private:
+ ShadeWidget *m_red_shade;
+ ShadeWidget *m_green_shade;
+ ShadeWidget *m_blue_shade;
+ ShadeWidget *m_alpha_shade;
+};
+
+
+class GradientRenderer : public ArthurFrame
+{
+ Q_OBJECT
+public:
+ GradientRenderer(QWidget *parent);
+ void paint(QPainter *p);
+
+ QSize sizeHint() const { return QSize(400, 400); }
+
+ HoverPoints *hoverPoints() const { return m_hoverPoints; }
+ void mousePressEvent(QMouseEvent *e);
+
+public slots:
+ void setGradientStops(const QGradientStops &stops);
+
+ void setPadSpread() { m_spread = QGradient::PadSpread; update(); }
+ void setRepeatSpread() { m_spread = QGradient::RepeatSpread; update(); }
+ void setReflectSpread() { m_spread = QGradient::ReflectSpread; update(); }
+
+ void setLinearGradient() { m_gradientType = Qt::LinearGradientPattern; update(); }
+ void setRadialGradient() { m_gradientType = Qt::RadialGradientPattern; update(); }
+ void setConicalGradient() { m_gradientType = Qt::ConicalGradientPattern; update(); }
+
+
+private:
+ QGradientStops m_stops;
+ HoverPoints *m_hoverPoints;
+
+ QGradient::Spread m_spread;
+ Qt::BrushStyle m_gradientType;
+};
+
+
+class GradientWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ GradientWidget(QWidget *parent);
+
+public slots:
+ void setDefault1() { setDefault(1); }
+ void setDefault2() { setDefault(2); }
+ void setDefault3() { setDefault(3); }
+ void setDefault4() { setDefault(4); }
+
+private:
+ void setDefault(int i);
+
+ GradientRenderer *m_renderer;
+ GradientEditor *m_editor;
+
+ QRadioButton *m_linearButton;
+ QRadioButton *m_radialButton;
+ QRadioButton *m_conicalButton;
+ QRadioButton *m_padSpreadButton;
+ QRadioButton *m_reflectSpreadButton;
+ QRadioButton *m_repeatSpreadButton;
+
+};
+
+#endif // GRADIENTS_H
diff --git a/demos/gradients/gradients.html b/demos/gradients/gradients.html
new file mode 100644
index 0000000..1ea2c0e
--- /dev/null
+++ b/demos/gradients/gradients.html
@@ -0,0 +1,31 @@
+<html>
+<center>
+<h2>Gradients</h2>
+</center>
+
+<p>In this demo we show the various types of gradients that can
+be used in Qt.</p>
+
+<p>There are three types of gradients:
+
+<ul>
+ <li><b>Linear</b> gradients interpolate colors between start and end
+ points.</li>
+ <li><b>Radial</b> gradients interpolate colors between a focal point and the
+ points on a circle surrounding it.</li>
+ <li><b>Conical</b> gradients interpolate colors around a center point.</li>
+</ul>
+
+</p>
+
+<p>The panel on the right contains a color table editor that defines
+the colors in the gradient. The three topmost controls determine the red,
+green and blue components while the last defines the alpha of the
+gradient. You can move points, and add new ones, by clicking with the left
+mouse button, and remove points by clicking with the right button.</p>
+
+<p>There are three default configurations available at the bottom of
+the page that are provided as suggestions on how a color table could be
+configured.</p>
+
+</html>
diff --git a/demos/gradients/gradients.pro b/demos/gradients/gradients.pro
new file mode 100644
index 0000000..7789896
--- /dev/null
+++ b/demos/gradients/gradients.pro
@@ -0,0 +1,20 @@
+SOURCES += main.cpp gradients.cpp
+HEADERS += gradients.h
+
+SHARED_FOLDER = ../shared
+
+include($$SHARED_FOLDER/shared.pri)
+
+RESOURCES += gradients.qrc
+contains(QT_CONFIG, opengl) {
+ DEFINES += QT_OPENGL_SUPPORT
+ QT += opengl
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/gradients
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.html
+sources.path = $$[QT_INSTALL_DEMOS]/gradients
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
diff --git a/demos/gradients/gradients.qrc b/demos/gradients/gradients.qrc
new file mode 100644
index 0000000..fb971eb
--- /dev/null
+++ b/demos/gradients/gradients.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/res/gradients">
+ <file>gradients.cpp</file>
+ <file>gradients.html</file>
+</qresource>
+</RCC>
diff --git a/demos/gradients/main.cpp b/demos/gradients/main.cpp
new file mode 100644
index 0000000..f880510
--- /dev/null
+++ b/demos/gradients/main.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gradients.h"
+
+#include <QApplication>
+
+int main(int argc, char **argv)
+{
+ Q_INIT_RESOURCE(gradients);
+
+ QApplication app(argc, argv);
+
+ GradientWidget gradientWidget(0);
+ QStyle *arthurStyle = new ArthurStyle();
+ gradientWidget.setStyle(arthurStyle);
+ QList<QWidget *> widgets = qFindChildren<QWidget *>(&gradientWidget);
+ foreach (QWidget *w, widgets)
+ w->setStyle(arthurStyle);
+ gradientWidget.show();
+
+ return app.exec();
+}
diff --git a/demos/interview/README b/demos/interview/README
new file mode 100644
index 0000000..5089442
--- /dev/null
+++ b/demos/interview/README
@@ -0,0 +1,2 @@
+The interview example shows the same model and selection being shared
+between three different views.
diff --git a/demos/interview/images/folder.png b/demos/interview/images/folder.png
new file mode 100644
index 0000000..589fd2d
--- /dev/null
+++ b/demos/interview/images/folder.png
Binary files differ
diff --git a/demos/interview/images/interview.png b/demos/interview/images/interview.png
new file mode 100644
index 0000000..0c3d690
--- /dev/null
+++ b/demos/interview/images/interview.png
Binary files differ
diff --git a/demos/interview/images/services.png b/demos/interview/images/services.png
new file mode 100644
index 0000000..6b2ad96
--- /dev/null
+++ b/demos/interview/images/services.png
Binary files differ
diff --git a/demos/interview/interview.pro b/demos/interview/interview.pro
new file mode 100644
index 0000000..19b2ca8
--- /dev/null
+++ b/demos/interview/interview.pro
@@ -0,0 +1,20 @@
+TEMPLATE = app
+
+CONFIG += qt warn_on
+HEADERS += model.h
+SOURCES += model.cpp main.cpp
+RESOURCES += interview.qrc
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/interview
+sources.files = $$SOURCES $$HEADERS $$RESOURCES README *.pro images
+sources.path = $$[QT_INSTALL_DEMOS]/interview
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
diff --git a/demos/interview/interview.qrc b/demos/interview/interview.qrc
new file mode 100644
index 0000000..b28ea34
--- /dev/null
+++ b/demos/interview/interview.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>images/folder.png</file>
+ <file>images/services.png</file>
+ <file>images/interview.png</file>
+</qresource>
+</RCC>
diff --git a/demos/interview/main.cpp b/demos/interview/main.cpp
new file mode 100644
index 0000000..9682322
--- /dev/null
+++ b/demos/interview/main.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "model.h"
+
+#include <QApplication>
+#include <QTableView>
+#include <QTreeView>
+#include <QListView>
+#include <QSplitter>
+#include <QHeaderView>
+
+int main(int argc, char *argv[])
+{
+ Q_INIT_RESOURCE(interview);
+
+ QApplication app(argc, argv);
+ QSplitter page;
+
+ QAbstractItemModel *data = new Model(1000, 10, &page);
+ QItemSelectionModel *selections = new QItemSelectionModel(data);
+
+ QTableView *table = new QTableView;
+ table->setModel(data);
+ table->setSelectionModel(selections);
+ table->horizontalHeader()->setMovable(true);
+ table->verticalHeader()->setMovable(true);
+ // Set StaticContents to enable minimal repaints on resizes.
+ table->viewport()->setAttribute(Qt::WA_StaticContents);
+ page.addWidget(table);
+
+ QTreeView *tree = new QTreeView;
+ tree->setModel(data);
+ tree->setSelectionModel(selections);
+ tree->setUniformRowHeights(true);
+ tree->header()->setStretchLastSection(false);
+ tree->viewport()->setAttribute(Qt::WA_StaticContents);
+ // Disable the focus rect to get minimal repaints when scrolling on Mac.
+ tree->setAttribute(Qt::WA_MacShowFocusRect, false);
+ page.addWidget(tree);
+
+ QListView *list = new QListView;
+ list->setModel(data);
+ list->setSelectionModel(selections);
+ list->setViewMode(QListView::IconMode);
+ list->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ list->setAlternatingRowColors(false);
+ list->viewport()->setAttribute(Qt::WA_StaticContents);
+ list->setAttribute(Qt::WA_MacShowFocusRect, false);
+ page.addWidget(list);
+
+ page.setWindowIcon(QPixmap(":/images/interview.png"));
+ page.setWindowTitle("Interview");
+ page.show();
+
+ return app.exec();
+}
diff --git a/demos/interview/model.cpp b/demos/interview/model.cpp
new file mode 100644
index 0000000..1d5040c
--- /dev/null
+++ b/demos/interview/model.cpp
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "model.h"
+#include <QIcon>
+#include <QPixmap>
+
+Model::Model(int rows, int columns, QObject *parent)
+ : QAbstractItemModel(parent),
+ rc(rows), cc(columns),
+ tree(new QVector<Node>(rows, Node(0)))
+{
+
+}
+
+Model::~Model()
+{
+ delete tree;
+}
+
+QModelIndex Model::index(int row, int column, const QModelIndex &parent) const
+{
+ if (row < rc && row >= 0 && column < cc && column >= 0) {
+ Node *p = static_cast<Node*>(parent.internalPointer());
+ Node *n = node(row, p);
+ if (n)
+ return createIndex(row, column, n);
+ }
+ return QModelIndex();
+}
+
+QModelIndex Model::parent(const QModelIndex &child) const
+{
+ if (child.isValid()) {
+ Node *n = static_cast<Node*>(child.internalPointer());
+ Node *p = parent(n);
+ if (p)
+ return createIndex(row(p), 0, p);
+ }
+ return QModelIndex();
+}
+
+int Model::rowCount(const QModelIndex &parent) const
+{
+ return (parent.isValid() && parent.column() != 0) ? 0 : rc;
+}
+
+int Model::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return cc;
+}
+
+QVariant Model::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+ if (role == Qt::DisplayRole)
+ return "Item " + QString::number(index.row()) + ":" + QString::number(index.column());
+ if (role == Qt::DecorationRole) {
+ if (index.column() == 0)
+ return iconProvider.icon(QFileIconProvider::Folder);
+ return iconProvider.icon(QFileIconProvider::File);
+ }
+ return QVariant();
+}
+
+QVariant Model::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ static QIcon services(QPixmap(":/images/services.png"));
+ if (role == Qt::DisplayRole)
+ return QString::number(section);
+ if (role == Qt::DecorationRole)
+ return qVariantFromValue(services);
+ return QAbstractItemModel::headerData(section, orientation, role);
+}
+
+bool Model::hasChildren(const QModelIndex &parent) const
+{
+ if (parent.isValid() && parent.column() != 0)
+ return false;
+ return rc > 0 && cc > 0;
+}
+
+Qt::ItemFlags Model::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+ return (Qt::ItemIsDragEnabled|Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+}
+
+Model::Node *Model::node(int row, Node *parent) const
+{
+ if (parent && !parent->children)
+ parent->children = new QVector<Node>(rc, Node(parent));
+ QVector<Node> *v = parent ? parent->children : tree;
+ return const_cast<Node*>(&(v->at(row)));
+}
+
+Model::Node *Model::parent(Node *child) const
+{
+ return child ? child->parent : 0;
+}
+
+int Model::row(Node *node) const
+{
+ const Node *first = node->parent ? &(node->parent->children->at(0)) : &(tree->at(0));
+ return (node - first);
+}
diff --git a/demos/interview/model.h b/demos/interview/model.h
new file mode 100644
index 0000000..96e6aea
--- /dev/null
+++ b/demos/interview/model.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MODEL_H
+#define MODEL_H
+
+#include <QAbstractItemModel>
+#include <QFileIconProvider>
+#include <QVector>
+
+class Model : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ Model(int rows, int columns, QObject *parent = 0);
+ ~Model();
+
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ QModelIndex parent(const QModelIndex &child) const;
+
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+
+ QVariant data(const QModelIndex &index, int role) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+ bool hasChildren(const QModelIndex &parent) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+
+private:
+
+ struct Node
+ {
+ Node(Node *parent = 0) : parent(parent), children(0) {}
+ ~Node() { delete children; }
+ Node *parent;
+ QVector<Node> *children;
+ };
+
+ Node *node(int row, Node *parent) const;
+ Node *parent(Node *child) const;
+ int row(Node *node) const;
+
+ int rc, cc;
+ QVector<Node> *tree;
+ QFileIconProvider iconProvider;
+};
+
+#endif
diff --git a/demos/macmainwindow/macmainwindow.h b/demos/macmainwindow/macmainwindow.h
new file mode 100644
index 0000000..b5e4740
--- /dev/null
+++ b/demos/macmainwindow/macmainwindow.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef MACMAINWINDOW_H
+#define MACMAINWINDOW_H
+
+#include <QtGui>
+
+#ifdef Q_WS_MAC
+
+#import <qmaccocoaviewcontainer_mac.h>
+
+#ifdef QT_MAC_USE_COCOA
+class SearchWidget : public QMacCocoaViewContainer
+{
+ Q_OBJECT
+public:
+ SearchWidget(QWidget *parent = 0);
+ ~SearchWidget();
+
+ QSize sizeHint() const;
+private:
+};
+
+#else
+#include <Carbon/Carbon.h>
+
+// The SearchWidget class wraps a native HISearchField.
+class SearchWidget : public QWidget
+{
+ Q_OBJECT
+private:
+ HIViewRef searchField;
+ CFStringRef searchFieldText;
+
+public:
+ QSize sizeHint() const;
+ SearchWidget(QWidget *parent = 0);
+ ~SearchWidget();
+};
+
+#endif
+
+QMenu *createMenu(QWidget *parent);
+
+class SearchWrapper : public QWidget
+{
+Q_OBJECT
+public:
+ SearchWrapper(QWidget *parent = 0);
+ QSize sizeHint() const;
+ QWidget *s;
+};
+
+class Spacer : public QWidget
+{
+Q_OBJECT
+public:
+ Spacer(QWidget *parent = 0);
+ QSize sizeHint() const;
+};
+
+class MacSplitterHandle : public QSplitterHandle
+{
+Q_OBJECT
+public:
+ MacSplitterHandle(Qt::Orientation orientation, QSplitter *parent);
+ void paintEvent(QPaintEvent *);
+ QSize sizeHint() const;
+};
+
+class MacSplitter : public QSplitter
+{
+public:
+ QSplitterHandle *createHandle();
+};
+
+class MacMainWindow : public QMainWindow
+{
+Q_OBJECT
+public:
+ MacMainWindow();
+ ~MacMainWindow();
+ QAbstractItemModel *createItemModel();
+ void resizeEvent(QResizeEvent *e);
+ QAbstractItemModel *createDocumentModel();
+public:
+ QSplitter *splitter;
+ QSplitter *horizontalSplitter;
+ QTreeView *sidebar;
+ QListView *documents;
+ QTextEdit *textedit;
+ QVBoxLayout *layout;
+ SearchWidget *searchWidget;
+ QToolBar * toolBar;
+};
+
+#endif // Q_WS_MAC
+
+#endif //MACMAINWINDOW_H
diff --git a/demos/macmainwindow/macmainwindow.mm b/demos/macmainwindow/macmainwindow.mm
new file mode 100644
index 0000000..156e793
--- /dev/null
+++ b/demos/macmainwindow/macmainwindow.mm
@@ -0,0 +1,347 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "macmainwindow.h"
+#import <Cocoa/Cocoa.h>
+#include <QtGui>
+
+
+#ifdef Q_WS_MAC
+
+#include <Carbon/Carbon.h>
+
+#ifdef QT_MAC_USE_COCOA
+
+//![0]
+SearchWidget::SearchWidget(QWidget *parent)
+ : QMacCocoaViewContainer(0, parent)
+{
+ // Many Cocoa objects create temporary autorelease objects,
+ // so create a pool to catch them.
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ // Create the NSSearchField, set it on the QCocoaViewContainer.
+ NSSearchField *search = [[NSSearchField alloc] init];
+ setCocoaView(search);
+
+ // Use a Qt menu for the search field menu.
+ QMenu *qtMenu = createMenu(this);
+ NSMenu *nsMenu = qtMenu->macMenu(0);
+ [[search cell] setSearchMenuTemplate:nsMenu];
+
+ // Release our reference, since our super class takes ownership and we
+ // don't need it anymore.
+ [search release];
+
+ // Clean up our pool as we no longer need it.
+ [pool release];
+}
+//![0]
+
+SearchWidget::~SearchWidget()
+{
+}
+
+QSize SearchWidget::sizeHint() const
+{
+ return QSize(150, 40);
+}
+
+#else
+
+// The SearchWidget class wraps a native HISearchField.
+SearchWidget::SearchWidget(QWidget *parent)
+ :QWidget(parent)
+{
+
+ // Create a native search field and pass its window id to QWidget::create.
+ searchFieldText = CFStringCreateWithCString(0, "search", 0);
+ HISearchFieldCreate(NULL/*bounds*/, kHISearchFieldAttributesSearchIcon | kHISearchFieldAttributesCancel,
+ NULL/*menu ref*/, searchFieldText, &searchField);
+ create(reinterpret_cast<WId>(searchField));
+
+ // Use a Qt menu for the search field menu.
+ QMenu *searchMenu = createMenu(this);
+ MenuRef menuRef = searchMenu->macMenu(0);
+ HISearchFieldSetSearchMenu(searchField, menuRef);
+ setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+}
+
+SearchWidget::~SearchWidget()
+{
+ CFRelease(searchField);
+ CFRelease(searchFieldText);
+}
+
+// Get the size hint from the search field.
+QSize SearchWidget::sizeHint() const
+{
+ EventRef event;
+ HIRect optimalBounds;
+ CreateEvent(0, kEventClassControl,
+ kEventControlGetOptimalBounds,
+ GetCurrentEventTime(),
+ kEventAttributeUserEvent, &event);
+
+ SendEventToEventTargetWithOptions(event,
+ HIObjectGetEventTarget(HIObjectRef(winId())),
+ kEventTargetDontPropagate);
+
+ GetEventParameter(event,
+ kEventParamControlOptimalBounds, typeHIRect,
+ 0, sizeof(HIRect), 0, &optimalBounds);
+
+ ReleaseEvent(event);
+ return QSize(optimalBounds.size.width + 100, // make it a bit wider.
+ optimalBounds.size.height);
+}
+
+#endif
+
+QMenu *createMenu(QWidget *parent)
+{
+ QMenu *searchMenu = new QMenu(parent);
+
+ QAction * indexAction = searchMenu->addAction("Index Search");
+ indexAction->setCheckable(true);
+ indexAction->setChecked(true);
+
+ QAction * fulltextAction = searchMenu->addAction("Full Text Search");
+ fulltextAction->setCheckable(true);
+
+ QActionGroup *searchActionGroup = new QActionGroup(parent);
+ searchActionGroup->addAction(indexAction);
+ searchActionGroup->addAction(fulltextAction);
+ searchActionGroup->setExclusive(true);
+
+ return searchMenu;
+}
+
+SearchWrapper::SearchWrapper(QWidget *parent)
+:QWidget(parent)
+{
+ s = new SearchWidget(this);
+ s->move(2,2);
+ setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+}
+
+QSize SearchWrapper::sizeHint() const
+{
+ return s->sizeHint() + QSize(6, 2);
+}
+
+Spacer::Spacer(QWidget *parent)
+:QWidget(parent)
+{
+ QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ setSizePolicy(sizePolicy);
+}
+
+QSize Spacer::sizeHint() const
+{
+ return QSize(1, 1);
+}
+
+MacSplitterHandle::MacSplitterHandle(Qt::Orientation orientation, QSplitter *parent)
+: QSplitterHandle(orientation, parent) { }
+
+// Paint the horizontal handle as a gradient, paint
+// the vertical handle as a line.
+void MacSplitterHandle::paintEvent(QPaintEvent *)
+{
+ QPainter painter(this);
+
+ QColor topColor(145, 145, 145);
+ QColor bottomColor(142, 142, 142);
+ QColor gradientStart(252, 252, 252);
+ QColor gradientStop(223, 223, 223);
+
+ if (orientation() == Qt::Vertical) {
+ painter.setPen(topColor);
+ painter.drawLine(0, 0, width(), 0);
+ painter.setPen(bottomColor);
+ painter.drawLine(0, height() - 1, width(), height() - 1);
+
+ QLinearGradient linearGrad(QPointF(0, 0), QPointF(0, height() -3));
+ linearGrad.setColorAt(0, gradientStart);
+ linearGrad.setColorAt(1, gradientStop);
+ painter.fillRect(QRect(QPoint(0,1), size() - QSize(0, 2)), QBrush(linearGrad));
+ } else {
+ painter.setPen(topColor);
+ painter.drawLine(0, 0, 0, height());
+ }
+}
+
+QSize MacSplitterHandle::sizeHint() const
+{
+ QSize parent = QSplitterHandle::sizeHint();
+ if (orientation() == Qt::Vertical) {
+ return parent + QSize(0, 3);
+ } else {
+ return QSize(1, parent.height());
+ }
+}
+
+QSplitterHandle *MacSplitter::createHandle()
+{
+ return new MacSplitterHandle(orientation(), this);
+}
+
+MacMainWindow::MacMainWindow()
+{
+ QSettings settings;
+ restoreGeometry(settings.value("Geometry").toByteArray());
+
+ setWindowTitle("Mac Main Window");
+
+ splitter = new MacSplitter();
+
+ // Set up the left-hand side blue side bar.
+ sidebar = new QTreeView();
+ sidebar->setFrameStyle(QFrame::NoFrame);
+ sidebar->setAttribute(Qt::WA_MacShowFocusRect, false);
+ sidebar->setAutoFillBackground(true);
+
+ // Set the palette.
+ QPalette palette = sidebar->palette();
+ QColor macSidebarColor(231, 237, 246);
+ QColor macSidebarHighlightColor(168, 183, 205);
+ palette.setColor(QPalette::Base, macSidebarColor);
+ palette.setColor(QPalette::Highlight, macSidebarHighlightColor);
+ sidebar->setPalette(palette);
+
+ sidebar->setModel(createItemModel());
+ sidebar->header()->hide();
+ sidebar->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ sidebar->setTextElideMode(Qt::ElideMiddle);
+
+ splitter->addWidget(sidebar);
+
+ horizontalSplitter = new MacSplitter();
+ horizontalSplitter->setOrientation(Qt::Vertical);
+ splitter->addWidget(horizontalSplitter);
+
+ splitter->setStretchFactor(0, 0);
+ splitter->setStretchFactor(1, 1);
+
+ // Set up the top document list view.
+ documents = new QListView();
+ documents->setFrameStyle(QFrame::NoFrame);
+ documents->setAttribute(Qt::WA_MacShowFocusRect, false);
+ documents->setModel(createDocumentModel());
+ documents->setAlternatingRowColors(true);
+ documents->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+ horizontalSplitter->addWidget(documents);
+ horizontalSplitter->setStretchFactor(0, 0);
+
+ // Set up the text view.
+ textedit = new QTextEdit();
+ textedit->setFrameStyle(QFrame::NoFrame);
+ textedit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+ textedit->setText("<br><br><br><br><br><br><center><b>This demo shows how to create a \
+ Qt main window application that has the same appearance as other \
+ Mac OS X applications such as Mail or iTunes. This includes \
+ customizing the item views and QSplitter and wrapping native widgets \
+ such as the search field.</b></center>");
+
+ horizontalSplitter->addWidget(textedit);
+
+ setCentralWidget(splitter);
+
+ toolBar = addToolBar(tr("Search"));
+ toolBar->addWidget(new Spacer());
+ toolBar->addWidget(new SearchWrapper());
+
+ setUnifiedTitleAndToolBarOnMac(true);
+}
+
+MacMainWindow::~MacMainWindow()
+{
+ QSettings settings;
+ settings.setValue("Geometry", saveGeometry());
+}
+
+QAbstractItemModel *MacMainWindow::createItemModel()
+{
+ QStandardItemModel *model = new QStandardItemModel();
+ QStandardItem *parentItem = model->invisibleRootItem();
+
+ QStandardItem *documentationItem = new QStandardItem("Documentation");
+ parentItem->appendRow(documentationItem);
+
+ QStandardItem *assistantItem = new QStandardItem("Qt MainWindow Manual");
+ documentationItem->appendRow(assistantItem);
+
+ QStandardItem *designerItem = new QStandardItem("Qt Designer Manual");
+ documentationItem->appendRow(designerItem);
+
+ QStandardItem *qtItem = new QStandardItem("Qt Reference Documentation");
+ qtItem->appendRow(new QStandardItem("Classes"));
+ qtItem->appendRow(new QStandardItem("Overviews"));
+ qtItem->appendRow(new QStandardItem("Tutorial & Examples"));
+ documentationItem->appendRow(qtItem);
+
+ QStandardItem *bookmarksItem = new QStandardItem("Bookmarks");
+ parentItem->appendRow(bookmarksItem);
+ bookmarksItem->appendRow(new QStandardItem("QWidget"));
+ bookmarksItem->appendRow(new QStandardItem("QObject"));
+ bookmarksItem->appendRow(new QStandardItem("QWizard"));
+
+ return model;
+}
+
+void MacMainWindow::resizeEvent(QResizeEvent *)
+{
+ if (toolBar)
+ toolBar->updateGeometry();
+}
+
+QAbstractItemModel *MacMainWindow::createDocumentModel()
+{
+ QStandardItemModel *model = new QStandardItemModel();
+ QStandardItem *parentItem = model->invisibleRootItem();
+ parentItem->appendRow(new QStandardItem("QWidget Class Reference"));
+ parentItem->appendRow(new QStandardItem("QObject Class Reference"));
+ parentItem->appendRow(new QStandardItem("QListView Class Reference"));
+
+ return model;
+}
+
+#endif // Q_WS_MAC
diff --git a/demos/macmainwindow/macmainwindow.pro b/demos/macmainwindow/macmainwindow.pro
new file mode 100644
index 0000000..cab3845
--- /dev/null
+++ b/demos/macmainwindow/macmainwindow.pro
@@ -0,0 +1,25 @@
+TEMPLATE = app
+TARGET = macmainwindow
+
+CONFIG += qt warn_on console
+
+OBJECTIVE_SOURCES += macmainwindow.mm
+SOURCES += main.cpp
+HEADERS += macmainwindow.h
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+LIBS += -framework Cocoa
+
+# install
+mac {
+target.path = $$[QT_INSTALL_DEMOS]/macmainwindow
+sources.files = $$SOURCES *.pro *.html
+sources.path = $$[QT_INSTALL_DEMOS]/macmainwindow
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+}
diff --git a/demos/macmainwindow/main.cpp b/demos/macmainwindow/main.cpp
new file mode 100644
index 0000000..2b01cfe
--- /dev/null
+++ b/demos/macmainwindow/main.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui>
+#include "macmainwindow.h"
+
+#ifdef Q_WS_MAC
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ MacMainWindow mainWindow;
+ mainWindow.show();
+ return app.exec();
+}
+
+#else
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ QLabel label;
+ label.resize(300, 200);
+ label.setText(" This demo requires Mac OS X.");
+ label.show();
+ return app.exec();
+}
+
+#endif
diff --git a/demos/mainwindow/colorswatch.cpp b/demos/mainwindow/colorswatch.cpp
new file mode 100644
index 0000000..ba6a076
--- /dev/null
+++ b/demos/mainwindow/colorswatch.cpp
@@ -0,0 +1,746 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "colorswatch.h"
+
+#include <QAction>
+#include <QtEvents>
+#include <QFrame>
+#include <QMainWindow>
+#include <QMenu>
+#include <QPainter>
+#include <QImage>
+#include <QColor>
+#include <QDialog>
+#include <QGridLayout>
+#include <QSpinBox>
+#include <QLabel>
+#include <QPainterPath>
+#include <QPushButton>
+#include <QHBoxLayout>
+#include <QBitmap>
+#include <QtDebug>
+
+#undef DEBUG_SIZEHINTS
+
+QColor bgColorForName(const QString &name)
+{
+ if (name == "Black")
+ return QColor("#D8D8D8");
+ else if (name == "White")
+ return QColor("#F1F1F1");
+ else if (name == "Red")
+ return QColor("#F1D8D8");
+ else if (name == "Green")
+ return QColor("#D8E4D8");
+ else if (name == "Blue")
+ return QColor("#D8D8F1");
+ else if (name == "Yellow")
+ return QColor("#F1F0D8");
+ return QColor(name).light(110);
+}
+
+QColor fgColorForName(const QString &name)
+{
+ if (name == "Black")
+ return QColor("#6C6C6C");
+ else if (name == "White")
+ return QColor("#F8F8F8");
+ else if (name == "Red")
+ return QColor("#F86C6C");
+ else if (name == "Green")
+ return QColor("#6CB26C");
+ else if (name == "Blue")
+ return QColor("#6C6CF8");
+ else if (name == "Yellow")
+ return QColor("#F8F76C");
+ return QColor(name);
+}
+
+class ColorDock : public QFrame
+{
+ Q_OBJECT
+public:
+ ColorDock(const QString &c, QWidget *parent);
+
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+
+ void setCustomSizeHint(const QSize &size);
+
+public slots:
+ void changeSizeHints();
+
+protected:
+ void paintEvent(QPaintEvent *);
+ QString color;
+ QSize szHint, minSzHint;
+};
+
+ColorDock::ColorDock(const QString &c, QWidget *parent)
+ : QFrame(parent) , color(c)
+{
+ QFont font = this->font();
+ font.setPointSize(8);
+ setFont(font);
+ szHint = QSize(-1, -1);
+ minSzHint = QSize(125, 75);
+}
+
+QSize ColorDock::sizeHint() const
+{
+ return szHint;
+}
+
+QSize ColorDock::minimumSizeHint() const
+{
+ return minSzHint;
+}
+
+void ColorDock::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ p.setRenderHint(QPainter::Antialiasing);
+ p.fillRect(rect(), bgColorForName(color));
+
+ p.save();
+
+ extern void render_qt_text(QPainter *, int, int, const QColor &);
+ render_qt_text(&p, width(), height(), fgColorForName(color));
+
+ p.restore();
+
+#ifdef DEBUG_SIZEHINTS
+ p.setRenderHint(QPainter::Antialiasing, false);
+
+ QSize sz = size();
+ QSize szHint = sizeHint();
+ QSize minSzHint = minimumSizeHint();
+ QSize maxSz = maximumSize();
+ QString text = QString::fromLatin1("sz: %1x%2\nszHint: %3x%4\nminSzHint: %5x%6\n"
+ "maxSz: %8x%9")
+ .arg(sz.width()).arg(sz.height())
+ .arg(szHint.width()).arg(szHint.height())
+ .arg(minSzHint.width()).arg(minSzHint.height())
+ .arg(maxSz.width()).arg(maxSz.height());
+
+ QRect r = fontMetrics().boundingRect(rect(), Qt::AlignLeft|Qt::AlignTop, text);
+ r.adjust(-2, -2, 1, 1);
+ p.translate(4, 4);
+ QColor bg = Qt::yellow;
+ bg.setAlpha(120);
+ p.setBrush(bg);
+ p.setPen(Qt::black);
+ p.drawRect(r);
+ p.drawText(rect(), Qt::AlignLeft|Qt::AlignTop, text);
+#endif // DEBUG_SIZEHINTS
+}
+
+static QSpinBox *createSpinBox(int value, QWidget *parent, int max = 1000)
+{
+ QSpinBox *result = new QSpinBox(parent);
+ result->setMinimum(-1);
+ result->setMaximum(max);
+ result->setValue(value);
+ return result;
+}
+
+void ColorDock::changeSizeHints()
+{
+ QDialog dialog(this);
+ dialog.setWindowTitle(color);
+
+ QVBoxLayout *topLayout = new QVBoxLayout(&dialog);
+
+ QGridLayout *inputLayout = new QGridLayout();
+ topLayout->addLayout(inputLayout);
+
+ inputLayout->addWidget(new QLabel(tr("Size Hint:"), &dialog), 0, 0);
+ inputLayout->addWidget(new QLabel(tr("Min Size Hint:"), &dialog), 1, 0);
+ inputLayout->addWidget(new QLabel(tr("Max Size:"), &dialog), 2, 0);
+ inputLayout->addWidget(new QLabel(tr("Dockwgt Max Size:"), &dialog), 3, 0);
+
+ QSpinBox *szHintW = createSpinBox(szHint.width(), &dialog);
+ inputLayout->addWidget(szHintW, 0, 1);
+ QSpinBox *szHintH = createSpinBox(szHint.height(), &dialog);
+ inputLayout->addWidget(szHintH, 0, 2);
+
+ QSpinBox *minSzHintW = createSpinBox(minSzHint.width(), &dialog);
+ inputLayout->addWidget(minSzHintW, 1, 1);
+ QSpinBox *minSzHintH = createSpinBox(minSzHint.height(), &dialog);
+ inputLayout->addWidget(minSzHintH, 1, 2);
+
+ QSize maxSz = maximumSize();
+ QSpinBox *maxSzW = createSpinBox(maxSz.width(), &dialog, QWIDGETSIZE_MAX);
+ inputLayout->addWidget(maxSzW, 2, 1);
+ QSpinBox *maxSzH = createSpinBox(maxSz.height(), &dialog, QWIDGETSIZE_MAX);
+ inputLayout->addWidget(maxSzH, 2, 2);
+
+ QSize dwMaxSz = parentWidget()->maximumSize();
+ QSpinBox *dwMaxSzW = createSpinBox(dwMaxSz.width(), &dialog, QWIDGETSIZE_MAX);
+ inputLayout->addWidget(dwMaxSzW, 3, 1);
+ QSpinBox *dwMaxSzH = createSpinBox(dwMaxSz.height(), &dialog, QWIDGETSIZE_MAX);
+ inputLayout->addWidget(dwMaxSzH, 3, 2);
+
+ inputLayout->setColumnStretch(1, 1);
+ inputLayout->setColumnStretch(2, 1);
+
+ topLayout->addStretch();
+
+ QHBoxLayout *buttonBox = new QHBoxLayout();
+ topLayout->addLayout(buttonBox);
+
+ QPushButton *okButton = new QPushButton(tr("Ok"), &dialog);
+ QPushButton *cancelButton = new QPushButton(tr("Cancel"), &dialog);
+ connect(okButton, SIGNAL(clicked()), &dialog, SLOT(accept()));
+ connect(cancelButton, SIGNAL(clicked()), &dialog, SLOT(reject()));
+ buttonBox->addStretch();
+ buttonBox->addWidget(cancelButton);
+ buttonBox->addWidget(okButton);
+
+
+ if (!dialog.exec())
+ return;
+
+ szHint = QSize(szHintW->value(), szHintH->value());
+ minSzHint = QSize(minSzHintW->value(), minSzHintH->value());
+ maxSz = QSize(maxSzW->value(), maxSzH->value());
+ setMaximumSize(maxSz);
+ dwMaxSz = QSize(dwMaxSzW->value(), dwMaxSzH->value());
+ parentWidget()->setMaximumSize(dwMaxSz);
+ updateGeometry();
+ update();
+}
+
+void ColorDock::setCustomSizeHint(const QSize &size)
+{
+ szHint = size;
+ updateGeometry();
+}
+
+ColorSwatch::ColorSwatch(const QString &colorName, QWidget *parent, Qt::WindowFlags flags)
+ : QDockWidget(parent, flags)
+{
+ setObjectName(colorName + QLatin1String(" Dock Widget"));
+ setWindowTitle(objectName() + QLatin1String(" [*]"));
+
+ QFrame *swatch = new ColorDock(colorName, this);
+ swatch->setFrameStyle(QFrame::Box | QFrame::Sunken);
+
+ setWidget(swatch);
+
+ changeSizeHintsAction = new QAction(tr("Change Size Hints"), this);
+ connect(changeSizeHintsAction, SIGNAL(triggered()), swatch, SLOT(changeSizeHints()));
+
+ closableAction = new QAction(tr("Closable"), this);
+ closableAction->setCheckable(true);
+ connect(closableAction, SIGNAL(triggered(bool)), SLOT(changeClosable(bool)));
+
+ movableAction = new QAction(tr("Movable"), this);
+ movableAction->setCheckable(true);
+ connect(movableAction, SIGNAL(triggered(bool)), SLOT(changeMovable(bool)));
+
+ floatableAction = new QAction(tr("Floatable"), this);
+ floatableAction->setCheckable(true);
+ connect(floatableAction, SIGNAL(triggered(bool)), SLOT(changeFloatable(bool)));
+
+ verticalTitleBarAction = new QAction(tr("Vertical title bar"), this);
+ verticalTitleBarAction->setCheckable(true);
+ connect(verticalTitleBarAction, SIGNAL(triggered(bool)),
+ SLOT(changeVerticalTitleBar(bool)));
+
+ floatingAction = new QAction(tr("Floating"), this);
+ floatingAction->setCheckable(true);
+ connect(floatingAction, SIGNAL(triggered(bool)), SLOT(changeFloating(bool)));
+
+ allowedAreasActions = new QActionGroup(this);
+ allowedAreasActions->setExclusive(false);
+
+ allowLeftAction = new QAction(tr("Allow on Left"), this);
+ allowLeftAction->setCheckable(true);
+ connect(allowLeftAction, SIGNAL(triggered(bool)), SLOT(allowLeft(bool)));
+
+ allowRightAction = new QAction(tr("Allow on Right"), this);
+ allowRightAction->setCheckable(true);
+ connect(allowRightAction, SIGNAL(triggered(bool)), SLOT(allowRight(bool)));
+
+ allowTopAction = new QAction(tr("Allow on Top"), this);
+ allowTopAction->setCheckable(true);
+ connect(allowTopAction, SIGNAL(triggered(bool)), SLOT(allowTop(bool)));
+
+ allowBottomAction = new QAction(tr("Allow on Bottom"), this);
+ allowBottomAction->setCheckable(true);
+ connect(allowBottomAction, SIGNAL(triggered(bool)), SLOT(allowBottom(bool)));
+
+ allowedAreasActions->addAction(allowLeftAction);
+ allowedAreasActions->addAction(allowRightAction);
+ allowedAreasActions->addAction(allowTopAction);
+ allowedAreasActions->addAction(allowBottomAction);
+
+ areaActions = new QActionGroup(this);
+ areaActions->setExclusive(true);
+
+ leftAction = new QAction(tr("Place on Left") , this);
+ leftAction->setCheckable(true);
+ connect(leftAction, SIGNAL(triggered(bool)), SLOT(placeLeft(bool)));
+
+ rightAction = new QAction(tr("Place on Right") , this);
+ rightAction->setCheckable(true);
+ connect(rightAction, SIGNAL(triggered(bool)), SLOT(placeRight(bool)));
+
+ topAction = new QAction(tr("Place on Top") , this);
+ topAction->setCheckable(true);
+ connect(topAction, SIGNAL(triggered(bool)), SLOT(placeTop(bool)));
+
+ bottomAction = new QAction(tr("Place on Bottom") , this);
+ bottomAction->setCheckable(true);
+ connect(bottomAction, SIGNAL(triggered(bool)), SLOT(placeBottom(bool)));
+
+ areaActions->addAction(leftAction);
+ areaActions->addAction(rightAction);
+ areaActions->addAction(topAction);
+ areaActions->addAction(bottomAction);
+
+ connect(movableAction, SIGNAL(triggered(bool)), areaActions, SLOT(setEnabled(bool)));
+
+ connect(movableAction, SIGNAL(triggered(bool)), allowedAreasActions, SLOT(setEnabled(bool)));
+
+ connect(floatableAction, SIGNAL(triggered(bool)), floatingAction, SLOT(setEnabled(bool)));
+
+ connect(floatingAction, SIGNAL(triggered(bool)), floatableAction, SLOT(setDisabled(bool)));
+ connect(movableAction, SIGNAL(triggered(bool)), floatableAction, SLOT(setEnabled(bool)));
+
+ tabMenu = new QMenu(this);
+ tabMenu->setTitle(tr("Tab into"));
+ connect(tabMenu, SIGNAL(triggered(QAction*)), this, SLOT(tabInto(QAction*)));
+
+ splitHMenu = new QMenu(this);
+ splitHMenu->setTitle(tr("Split horizontally into"));
+ connect(splitHMenu, SIGNAL(triggered(QAction*)), this, SLOT(splitInto(QAction*)));
+
+ splitVMenu = new QMenu(this);
+ splitVMenu->setTitle(tr("Split vertically into"));
+ connect(splitVMenu, SIGNAL(triggered(QAction*)), this, SLOT(splitInto(QAction*)));
+
+ windowModifiedAction = new QAction(tr("Modified"), this);
+ windowModifiedAction->setCheckable(true);
+ windowModifiedAction->setChecked(false);
+ connect(windowModifiedAction, SIGNAL(toggled(bool)), this, SLOT(setWindowModified(bool)));
+
+ menu = new QMenu(colorName, this);
+ menu->addAction(toggleViewAction());
+ QAction *action = menu->addAction(tr("Raise"));
+ connect(action, SIGNAL(triggered()), this, SLOT(raise()));
+ menu->addAction(changeSizeHintsAction);
+ menu->addSeparator();
+ menu->addAction(closableAction);
+ menu->addAction(movableAction);
+ menu->addAction(floatableAction);
+ menu->addAction(floatingAction);
+ menu->addAction(verticalTitleBarAction);
+ menu->addSeparator();
+ menu->addActions(allowedAreasActions->actions());
+ menu->addSeparator();
+ menu->addActions(areaActions->actions());
+ menu->addSeparator();
+ menu->addMenu(splitHMenu);
+ menu->addMenu(splitVMenu);
+ menu->addMenu(tabMenu);
+ menu->addSeparator();
+ menu->addAction(windowModifiedAction);
+
+ connect(menu, SIGNAL(aboutToShow()), this, SLOT(updateContextMenu()));
+
+ if(colorName == "Black") {
+ leftAction->setShortcut(Qt::CTRL|Qt::Key_W);
+ rightAction->setShortcut(Qt::CTRL|Qt::Key_E);
+ toggleViewAction()->setShortcut(Qt::CTRL|Qt::Key_R);
+ }
+}
+
+void ColorSwatch::updateContextMenu()
+{
+ QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
+ const Qt::DockWidgetArea area = mainWindow->dockWidgetArea(this);
+ const Qt::DockWidgetAreas areas = allowedAreas();
+
+ closableAction->setChecked(features() & QDockWidget::DockWidgetClosable);
+ if (windowType() == Qt::Drawer) {
+ floatableAction->setEnabled(false);
+ floatingAction->setEnabled(false);
+ movableAction->setEnabled(false);
+ verticalTitleBarAction->setChecked(false);
+ } else {
+ floatableAction->setChecked(features() & QDockWidget::DockWidgetFloatable);
+ floatingAction->setChecked(isWindow());
+ // done after floating, to get 'floatable' correctly initialized
+ movableAction->setChecked(features() & QDockWidget::DockWidgetMovable);
+ verticalTitleBarAction
+ ->setChecked(features() & QDockWidget::DockWidgetVerticalTitleBar);
+ }
+
+ allowLeftAction->setChecked(isAreaAllowed(Qt::LeftDockWidgetArea));
+ allowRightAction->setChecked(isAreaAllowed(Qt::RightDockWidgetArea));
+ allowTopAction->setChecked(isAreaAllowed(Qt::TopDockWidgetArea));
+ allowBottomAction->setChecked(isAreaAllowed(Qt::BottomDockWidgetArea));
+
+ if (allowedAreasActions->isEnabled()) {
+ allowLeftAction->setEnabled(area != Qt::LeftDockWidgetArea);
+ allowRightAction->setEnabled(area != Qt::RightDockWidgetArea);
+ allowTopAction->setEnabled(area != Qt::TopDockWidgetArea);
+ allowBottomAction->setEnabled(area != Qt::BottomDockWidgetArea);
+ }
+
+ leftAction->blockSignals(true);
+ rightAction->blockSignals(true);
+ topAction->blockSignals(true);
+ bottomAction->blockSignals(true);
+
+ leftAction->setChecked(area == Qt::LeftDockWidgetArea);
+ rightAction->setChecked(area == Qt::RightDockWidgetArea);
+ topAction->setChecked(area == Qt::TopDockWidgetArea);
+ bottomAction->setChecked(area == Qt::BottomDockWidgetArea);
+
+ leftAction->blockSignals(false);
+ rightAction->blockSignals(false);
+ topAction->blockSignals(false);
+ bottomAction->blockSignals(false);
+
+ if (areaActions->isEnabled()) {
+ leftAction->setEnabled(areas & Qt::LeftDockWidgetArea);
+ rightAction->setEnabled(areas & Qt::RightDockWidgetArea);
+ topAction->setEnabled(areas & Qt::TopDockWidgetArea);
+ bottomAction->setEnabled(areas & Qt::BottomDockWidgetArea);
+ }
+
+ tabMenu->clear();
+ splitHMenu->clear();
+ splitVMenu->clear();
+ QList<ColorSwatch*> dock_list = qFindChildren<ColorSwatch*>(mainWindow);
+ foreach (ColorSwatch *dock, dock_list) {
+// if (!dock->isVisible() || dock->isFloating())
+// continue;
+ tabMenu->addAction(dock->objectName());
+ splitHMenu->addAction(dock->objectName());
+ splitVMenu->addAction(dock->objectName());
+ }
+}
+
+void ColorSwatch::splitInto(QAction *action)
+{
+ QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
+ QList<ColorSwatch*> dock_list = qFindChildren<ColorSwatch*>(mainWindow);
+ ColorSwatch *target = 0;
+ foreach (ColorSwatch *dock, dock_list) {
+ if (action->text() == dock->objectName()) {
+ target = dock;
+ break;
+ }
+ }
+ if (target == 0)
+ return;
+
+ Qt::Orientation o = action->parent() == splitHMenu
+ ? Qt::Horizontal : Qt::Vertical;
+ mainWindow->splitDockWidget(target, this, o);
+}
+
+void ColorSwatch::tabInto(QAction *action)
+{
+ QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
+ QList<ColorSwatch*> dock_list = qFindChildren<ColorSwatch*>(mainWindow);
+ ColorSwatch *target = 0;
+ foreach (ColorSwatch *dock, dock_list) {
+ if (action->text() == dock->objectName()) {
+ target = dock;
+ break;
+ }
+ }
+ if (target == 0)
+ return;
+
+ mainWindow->tabifyDockWidget(target, this);
+}
+
+void ColorSwatch::contextMenuEvent(QContextMenuEvent *event)
+{
+ event->accept();
+ menu->exec(event->globalPos());
+}
+
+void ColorSwatch::resizeEvent(QResizeEvent *e)
+{
+ if (BlueTitleBar *btb = qobject_cast<BlueTitleBar*>(titleBarWidget()))
+ btb->updateMask();
+
+ QDockWidget::resizeEvent(e);
+}
+
+
+void ColorSwatch::allow(Qt::DockWidgetArea area, bool a)
+{
+ Qt::DockWidgetAreas areas = allowedAreas();
+ areas = a ? areas | area : areas & ~area;
+ setAllowedAreas(areas);
+
+ if (areaActions->isEnabled()) {
+ leftAction->setEnabled(areas & Qt::LeftDockWidgetArea);
+ rightAction->setEnabled(areas & Qt::RightDockWidgetArea);
+ topAction->setEnabled(areas & Qt::TopDockWidgetArea);
+ bottomAction->setEnabled(areas & Qt::BottomDockWidgetArea);
+ }
+}
+
+void ColorSwatch::place(Qt::DockWidgetArea area, bool p)
+{
+ if (!p) return;
+
+ QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
+ mainWindow->addDockWidget(area, this);
+
+ if (allowedAreasActions->isEnabled()) {
+ allowLeftAction->setEnabled(area != Qt::LeftDockWidgetArea);
+ allowRightAction->setEnabled(area != Qt::RightDockWidgetArea);
+ allowTopAction->setEnabled(area != Qt::TopDockWidgetArea);
+ allowBottomAction->setEnabled(area != Qt::BottomDockWidgetArea);
+ }
+}
+
+void ColorSwatch::setCustomSizeHint(const QSize &size)
+{
+ if (ColorDock *dock = qobject_cast<ColorDock*>(widget()))
+ dock->setCustomSizeHint(size);
+}
+
+void ColorSwatch::changeClosable(bool on)
+{ setFeatures(on ? features() | DockWidgetClosable : features() & ~DockWidgetClosable); }
+
+void ColorSwatch::changeMovable(bool on)
+{ setFeatures(on ? features() | DockWidgetMovable : features() & ~DockWidgetMovable); }
+
+void ColorSwatch::changeFloatable(bool on)
+{ setFeatures(on ? features() | DockWidgetFloatable : features() & ~DockWidgetFloatable); }
+
+void ColorSwatch::changeFloating(bool floating)
+{ setFloating(floating); }
+
+void ColorSwatch::allowLeft(bool a)
+{ allow(Qt::LeftDockWidgetArea, a); }
+
+void ColorSwatch::allowRight(bool a)
+{ allow(Qt::RightDockWidgetArea, a); }
+
+void ColorSwatch::allowTop(bool a)
+{ allow(Qt::TopDockWidgetArea, a); }
+
+void ColorSwatch::allowBottom(bool a)
+{ allow(Qt::BottomDockWidgetArea, a); }
+
+void ColorSwatch::placeLeft(bool p)
+{ place(Qt::LeftDockWidgetArea, p); }
+
+void ColorSwatch::placeRight(bool p)
+{ place(Qt::RightDockWidgetArea, p); }
+
+void ColorSwatch::placeTop(bool p)
+{ place(Qt::TopDockWidgetArea, p); }
+
+void ColorSwatch::placeBottom(bool p)
+{ place(Qt::BottomDockWidgetArea, p); }
+
+void ColorSwatch::changeVerticalTitleBar(bool on)
+{
+ setFeatures(on ? features() | DockWidgetVerticalTitleBar
+ : features() & ~DockWidgetVerticalTitleBar);
+}
+
+QSize BlueTitleBar::minimumSizeHint() const
+{
+ QDockWidget *dw = qobject_cast<QDockWidget*>(parentWidget());
+ Q_ASSERT(dw != 0);
+ QSize result(leftPm.width() + rightPm.width(), centerPm.height());
+ if (dw->features() & QDockWidget::DockWidgetVerticalTitleBar)
+ result.transpose();
+ return result;
+}
+
+BlueTitleBar::BlueTitleBar(QWidget *parent)
+ : QWidget(parent)
+{
+ leftPm = QPixmap(":/res/titlebarLeft.png");
+ centerPm = QPixmap(":/res/titlebarCenter.png");
+ rightPm = QPixmap(":/res/titlebarRight.png");
+}
+
+void BlueTitleBar::paintEvent(QPaintEvent*)
+{
+ QPainter painter(this);
+ QRect rect = this->rect();
+
+ QDockWidget *dw = qobject_cast<QDockWidget*>(parentWidget());
+ Q_ASSERT(dw != 0);
+
+ if (dw->features() & QDockWidget::DockWidgetVerticalTitleBar) {
+ QSize s = rect.size();
+ s.transpose();
+ rect.setSize(s);
+
+ painter.translate(rect.left(), rect.top() + rect.width());
+ painter.rotate(-90);
+ painter.translate(-rect.left(), -rect.top());
+ }
+
+ painter.drawPixmap(rect.topLeft(), leftPm);
+ painter.drawPixmap(rect.topRight() - QPoint(rightPm.width() - 1, 0), rightPm);
+ QBrush brush(centerPm);
+ painter.fillRect(rect.left() + leftPm.width(), rect.top(),
+ rect.width() - leftPm.width() - rightPm.width(),
+ centerPm.height(), centerPm);
+}
+
+void BlueTitleBar::mousePressEvent(QMouseEvent *event)
+{
+ QPoint pos = event->pos();
+
+ QRect rect = this->rect();
+
+ QDockWidget *dw = qobject_cast<QDockWidget*>(parentWidget());
+ Q_ASSERT(dw != 0);
+
+ if (dw->features() & QDockWidget::DockWidgetVerticalTitleBar) {
+ QPoint p = pos;
+ pos.setX(rect.left() + rect.bottom() - p.y());
+ pos.setY(rect.top() + p.x() - rect.left());
+
+ QSize s = rect.size();
+ s.transpose();
+ rect.setSize(s);
+ }
+
+ const int buttonRight = 7;
+ const int buttonWidth = 20;
+ int right = rect.right() - pos.x();
+ int button = (right - buttonRight)/buttonWidth;
+ switch (button) {
+ case 0:
+ event->accept();
+ dw->close();
+ break;
+ case 1:
+ event->accept();
+ dw->setFloating(!dw->isFloating());
+ break;
+ case 2: {
+ event->accept();
+ QDockWidget::DockWidgetFeatures features = dw->features();
+ if (features & QDockWidget::DockWidgetVerticalTitleBar)
+ features &= ~QDockWidget::DockWidgetVerticalTitleBar;
+ else
+ features |= QDockWidget::DockWidgetVerticalTitleBar;
+ dw->setFeatures(features);
+ break;
+ }
+ default:
+ event->ignore();
+ break;
+ }
+}
+
+void BlueTitleBar::updateMask()
+{
+ QDockWidget *dw = qobject_cast<QDockWidget*>(parent());
+ Q_ASSERT(dw != 0);
+
+ QRect rect = dw->rect();
+ QPixmap bitmap(dw->size());
+
+ {
+ QPainter painter(&bitmap);
+
+ ///initialize to transparent
+ painter.fillRect(rect, Qt::color0);
+
+ QRect contents = rect;
+ contents.setTopLeft(geometry().bottomLeft());
+ contents.setRight(geometry().right());
+ contents.setBottom(contents.bottom()-y());
+ painter.fillRect(contents, Qt::color1);
+
+
+
+ //let's pait the titlebar
+
+ QRect titleRect = this->geometry();
+
+ if (dw->features() & QDockWidget::DockWidgetVerticalTitleBar) {
+ QSize s = rect.size();
+ s.transpose();
+ rect.setSize(s);
+
+ QSize s2 = size();
+ s2.transpose();
+ titleRect.setSize(s2);
+
+ painter.translate(rect.left(), rect.top() + rect.width());
+ painter.rotate(-90);
+ painter.translate(-rect.left(), -rect.top());
+ }
+
+ contents.setTopLeft(titleRect.bottomLeft());
+ contents.setRight(titleRect.right());
+ contents.setBottom(rect.bottom()-y());
+
+ QRect rect = titleRect;
+
+
+ painter.drawPixmap(rect.topLeft(), leftPm.mask());
+ painter.fillRect(rect.left() + leftPm.width(), rect.top(),
+ rect.width() - leftPm.width() - rightPm.width(),
+ centerPm.height(), Qt::color1);
+ painter.drawPixmap(rect.topRight() - QPoint(rightPm.width() - 1, 0), rightPm.mask());
+
+ painter.fillRect(contents, Qt::color1);
+ }
+
+ dw->setMask(bitmap);
+}
+
+#include "colorswatch.moc"
diff --git a/demos/mainwindow/colorswatch.h b/demos/mainwindow/colorswatch.h
new file mode 100644
index 0000000..57c5ac6
--- /dev/null
+++ b/demos/mainwindow/colorswatch.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef COLORSWATCH_H
+#define COLORSWATCH_H
+
+#include <QDockWidget>
+
+QT_FORWARD_DECLARE_CLASS(QAction)
+QT_FORWARD_DECLARE_CLASS(QActionGroup)
+QT_FORWARD_DECLARE_CLASS(QMenu)
+
+class ColorSwatch : public QDockWidget
+{
+ Q_OBJECT
+
+ QAction *closableAction;
+ QAction *movableAction;
+ QAction *floatableAction;
+ QAction *floatingAction;
+ QAction *verticalTitleBarAction;
+
+ QActionGroup *allowedAreasActions;
+ QAction *allowLeftAction;
+ QAction *allowRightAction;
+ QAction *allowTopAction;
+ QAction *allowBottomAction;
+
+ QActionGroup *areaActions;
+ QAction *leftAction;
+ QAction *rightAction;
+ QAction *topAction;
+ QAction *bottomAction;
+
+ QAction *changeSizeHintsAction;
+
+ QMenu *tabMenu;
+ QMenu *splitHMenu;
+ QMenu *splitVMenu;
+
+ QAction *windowModifiedAction;
+
+public:
+ ColorSwatch(const QString &colorName, QWidget *parent = 0, Qt::WindowFlags flags = 0);
+
+ QMenu *menu;
+ void setCustomSizeHint(const QSize &size);
+
+protected:
+ virtual void contextMenuEvent(QContextMenuEvent *event);
+ virtual void resizeEvent(QResizeEvent *e);
+
+private:
+ void allow(Qt::DockWidgetArea area, bool allow);
+ void place(Qt::DockWidgetArea area, bool place);
+
+private slots:
+ void changeClosable(bool on);
+ void changeMovable(bool on);
+ void changeFloatable(bool on);
+ void changeFloating(bool on);
+ void changeVerticalTitleBar(bool on);
+ void updateContextMenu();
+
+ void allowLeft(bool a);
+ void allowRight(bool a);
+ void allowTop(bool a);
+ void allowBottom(bool a);
+
+ void placeLeft(bool p);
+ void placeRight(bool p);
+ void placeTop(bool p);
+ void placeBottom(bool p);
+
+ void splitInto(QAction *action);
+ void tabInto(QAction *action);
+};
+
+class BlueTitleBar : public QWidget
+{
+ Q_OBJECT
+public:
+ BlueTitleBar(QWidget *parent = 0);
+
+ QSize sizeHint() const { return minimumSizeHint(); }
+ QSize minimumSizeHint() const;
+protected:
+ void paintEvent(QPaintEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+public slots:
+ void updateMask();
+
+private:
+ QPixmap leftPm, centerPm, rightPm;
+};
+
+
+#endif
diff --git a/demos/mainwindow/main.cpp b/demos/mainwindow/main.cpp
new file mode 100644
index 0000000..46268b5
--- /dev/null
+++ b/demos/mainwindow/main.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+
+#include <QApplication>
+#include <QPainterPath>
+#include <QPainter>
+#include <QMap>
+#include <qdebug.h>
+
+void render_qt_text(QPainter *painter, int w, int h, const QColor &color) {
+ QPainterPath path;
+ path.moveTo(-0.083695, 0.283849);
+ path.cubicTo(-0.049581, 0.349613, -0.012720, 0.397969, 0.026886, 0.428917);
+ path.cubicTo(0.066493, 0.459865, 0.111593, 0.477595, 0.162186, 0.482108);
+ path.lineTo(0.162186, 0.500000);
+ path.cubicTo(0.115929, 0.498066, 0.066565, 0.487669, 0.014094, 0.468810);
+ path.cubicTo(-0.038378, 0.449952, -0.088103, 0.423839, -0.135082, 0.390474);
+ path.cubicTo(-0.182061, 0.357108, -0.222608, 0.321567, -0.256722, 0.283849);
+ path.cubicTo(-0.304712, 0.262250, -0.342874, 0.239362, -0.371206, 0.215184);
+ path.cubicTo(-0.411969, 0.179078, -0.443625, 0.134671, -0.466175, 0.081963);
+ path.cubicTo(-0.488725, 0.029255, -0.500000, -0.033043, -0.500000, -0.104932);
+ path.cubicTo(-0.500000, -0.218407, -0.467042, -0.312621, -0.401127, -0.387573);
+ path.cubicTo(-0.335212, -0.462524, -0.255421, -0.500000, -0.161752, -0.500000);
+ path.cubicTo(-0.072998, -0.500000, 0.003903, -0.462444, 0.068951, -0.387331);
+ path.cubicTo(0.133998, -0.312218, 0.166522, -0.217440, 0.166522, -0.102998);
+ path.cubicTo(0.166522, -0.010155, 0.143394, 0.071325, 0.097138, 0.141441);
+ path.cubicTo(0.050882, 0.211557, -0.009396, 0.259026, -0.083695, 0.283849);
+ path.moveTo(-0.167823, -0.456963);
+ path.cubicTo(-0.228823, -0.456963, -0.277826, -0.432624, -0.314831, -0.383946);
+ path.cubicTo(-0.361665, -0.323340, -0.385082, -0.230335, -0.385082, -0.104932);
+ path.cubicTo(-0.385082, 0.017569, -0.361376, 0.112025, -0.313964, 0.178433);
+ path.cubicTo(-0.277248, 0.229368, -0.228534, 0.254836, -0.167823, 0.254836);
+ path.cubicTo(-0.105088, 0.254836, -0.054496, 0.229368, -0.016045, 0.178433);
+ path.cubicTo(0.029055, 0.117827, 0.051605, 0.028691, 0.051605, -0.088975);
+ path.cubicTo(0.051605, -0.179562, 0.039318, -0.255803, 0.014744, -0.317698);
+ path.cubicTo(-0.004337, -0.365409, -0.029705, -0.400548, -0.061362, -0.423114);
+ path.cubicTo(-0.093018, -0.445680, -0.128505, -0.456963, -0.167823, -0.456963);
+ path.moveTo(0.379011, -0.404739);
+ path.lineTo(0.379011, -0.236460);
+ path.lineTo(0.486123, -0.236460);
+ path.lineTo(0.486123, -0.197292);
+ path.lineTo(0.379011, -0.197292);
+ path.lineTo(0.379011, 0.134913);
+ path.cubicTo(0.379011, 0.168117, 0.383276, 0.190442, 0.391804, 0.201886);
+ path.cubicTo(0.400332, 0.213330, 0.411246, 0.219052, 0.424545, 0.219052);
+ path.cubicTo(0.435531, 0.219052, 0.446227, 0.215264, 0.456635, 0.207689);
+ path.cubicTo(0.467042, 0.200113, 0.474993, 0.188910, 0.480486, 0.174081);
+ path.lineTo(0.500000, 0.174081);
+ path.cubicTo(0.488436, 0.210509, 0.471957, 0.237911, 0.450564, 0.256286);
+ path.cubicTo(0.429170, 0.274662, 0.407054, 0.283849, 0.384215, 0.283849);
+ path.cubicTo(0.368893, 0.283849, 0.353859, 0.279094, 0.339115, 0.269584);
+ path.cubicTo(0.324371, 0.260074, 0.313530, 0.246534, 0.306592, 0.228965);
+ path.cubicTo(0.299653, 0.211396, 0.296184, 0.184075, 0.296184, 0.147002);
+ path.lineTo(0.296184, -0.197292);
+ path.lineTo(0.223330, -0.197292);
+ path.lineTo(0.223330, -0.215667);
+ path.cubicTo(0.241833, -0.224049, 0.260697, -0.237992, 0.279922, -0.257495);
+ path.cubicTo(0.299147, -0.276999, 0.316276, -0.300129, 0.331310, -0.326886);
+ path.cubicTo(0.338826, -0.341070, 0.349523, -0.367021, 0.363400, -0.404739);
+ path.lineTo(0.379011, -0.404739);
+ path.moveTo(-0.535993, 0.275629);
+
+ painter->translate(w / 2, h / 2);
+ double scale = qMin(w, h) * 8 / 10.0;
+ painter->scale(scale, scale);
+
+ painter->setRenderHint(QPainter::Antialiasing);
+
+ painter->save();
+ painter->translate(.1, .1);
+ painter->fillPath(path, QColor(0, 0, 0, 63));
+ painter->restore();
+
+ painter->setBrush(color);
+ painter->setPen(QPen(Qt::black, 0.02, Qt::SolidLine, Qt::FlatCap, Qt::RoundJoin));
+ painter->drawPath(path);
+}
+
+void usage()
+{
+ qWarning() << "Usage: mainwindow [-SizeHint<color> <width>x<height>] ...";
+ exit(1);
+}
+
+QMap<QString, QSize> parseCustomSizeHints(int argc, char **argv)
+{
+ QMap<QString, QSize> result;
+
+ for (int i = 1; i < argc; ++i) {
+ QString arg = QString::fromLocal8Bit(argv[i]);
+
+ if (arg.startsWith(QLatin1String("-SizeHint"))) {
+ QString name = arg.mid(9);
+ if (name.isEmpty())
+ usage();
+ if (++i == argc)
+ usage();
+ QString sizeStr = QString::fromLocal8Bit(argv[i]);
+ int idx = sizeStr.indexOf(QLatin1Char('x'));
+ if (idx == -1)
+ usage();
+ bool ok;
+ int w = sizeStr.left(idx).toInt(&ok);
+ if (!ok)
+ usage();
+ int h = sizeStr.mid(idx + 1).toInt(&ok);
+ if (!ok)
+ usage();
+ result[name] = QSize(w, h);
+ }
+ }
+
+ return result;
+}
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ QMap<QString, QSize> customSizeHints = parseCustomSizeHints(argc, argv);
+ MainWindow mainWin(customSizeHints);
+ mainWin.resize(800, 600);
+ mainWin.show();
+ return app.exec();
+}
diff --git a/demos/mainwindow/mainwindow.cpp b/demos/mainwindow/mainwindow.cpp
new file mode 100644
index 0000000..7edaf52
--- /dev/null
+++ b/demos/mainwindow/mainwindow.cpp
@@ -0,0 +1,510 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+#include "colorswatch.h"
+#include "toolbar.h"
+
+#include <QAction>
+#include <QLayout>
+#include <QMenu>
+#include <QMenuBar>
+#include <QStatusBar>
+#include <QTextEdit>
+#include <QFile>
+#include <QDataStream>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QSignalMapper>
+#include <QApplication>
+#include <QPainter>
+#include <QMouseEvent>
+#include <QLineEdit>
+#include <QComboBox>
+#include <QLabel>
+#include <QPushButton>
+#include <qdebug.h>
+
+static const char * const message =
+ "<p><b>Qt Main Window Demo</b></p>"
+
+ "<p>This is a demonstration of the QMainWindow, QToolBar and "
+ "QDockWidget classes.</p>"
+
+ "<p>The tool bar and dock widgets can be dragged around and rearranged "
+ "using the mouse or via the menu.</p>"
+
+ "<p>Each dock widget contains a colored frame and a context "
+ "(right-click) menu.</p>"
+
+#ifdef Q_WS_MAC
+ "<p>On Mac OS X, the \"Black\" dock widget has been created as a "
+ "<em>Drawer</em>, which is a special kind of QDockWidget.</p>"
+#endif
+ ;
+
+MainWindow::MainWindow(const QMap<QString, QSize> &customSizeHints,
+ QWidget *parent, Qt::WindowFlags flags)
+ : QMainWindow(parent, flags)
+{
+ setObjectName("MainWindow");
+ setWindowTitle("Qt Main Window Demo");
+
+ center = new QTextEdit(this);
+ center->setReadOnly(true);
+ center->setMinimumSize(400, 205);
+ setCentralWidget(center);
+
+ setupToolBar();
+ setupMenuBar();
+ setupDockWidgets(customSizeHints);
+
+ statusBar()->showMessage(tr("Status Bar"));
+}
+
+void MainWindow::actionTriggered(QAction *action)
+{
+ qDebug("action '%s' triggered", action->text().toLocal8Bit().data());
+}
+
+void MainWindow::setupToolBar()
+{
+ for (int i = 0; i < 3; ++i) {
+ ToolBar *tb = new ToolBar(QString::fromLatin1("Tool Bar %1").arg(i + 1), this);
+ toolBars.append(tb);
+ addToolBar(tb);
+ }
+}
+
+void MainWindow::setupMenuBar()
+{
+ QMenu *menu = menuBar()->addMenu(tr("&File"));
+
+ QAction *action = menu->addAction(tr("Save layout..."));
+ connect(action, SIGNAL(triggered()), this, SLOT(saveLayout()));
+
+ action = menu->addAction(tr("Load layout..."));
+ connect(action, SIGNAL(triggered()), this, SLOT(loadLayout()));
+
+ action = menu->addAction(tr("Switch layout direction"));
+ connect(action, SIGNAL(triggered()), this, SLOT(switchLayoutDirection()));
+
+ menu->addSeparator();
+
+ menu->addAction(tr("&Quit"), this, SLOT(close()));
+
+ mainWindowMenu = menuBar()->addMenu(tr("Main window"));
+
+ action = mainWindowMenu->addAction(tr("Animated docks"));
+ action->setCheckable(true);
+ action->setChecked(dockOptions() & AnimatedDocks);
+ connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions()));
+
+ action = mainWindowMenu->addAction(tr("Allow nested docks"));
+ action->setCheckable(true);
+ action->setChecked(dockOptions() & AllowNestedDocks);
+ connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions()));
+
+ action = mainWindowMenu->addAction(tr("Allow tabbed docks"));
+ action->setCheckable(true);
+ action->setChecked(dockOptions() & AllowTabbedDocks);
+ connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions()));
+
+ action = mainWindowMenu->addAction(tr("Force tabbed docks"));
+ action->setCheckable(true);
+ action->setChecked(dockOptions() & ForceTabbedDocks);
+ connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions()));
+
+ action = mainWindowMenu->addAction(tr("Vertical tabs"));
+ action->setCheckable(true);
+ action->setChecked(dockOptions() & VerticalTabs);
+ connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions()));
+
+ QMenu *toolBarMenu = menuBar()->addMenu(tr("Tool bars"));
+ for (int i = 0; i < toolBars.count(); ++i)
+ toolBarMenu->addMenu(toolBars.at(i)->menu);
+
+ dockWidgetMenu = menuBar()->addMenu(tr("&Dock Widgets"));
+}
+
+void MainWindow::setDockOptions()
+{
+ DockOptions opts;
+ QList<QAction*> actions = mainWindowMenu->actions();
+
+ if (actions.at(0)->isChecked())
+ opts |= AnimatedDocks;
+ if (actions.at(1)->isChecked())
+ opts |= AllowNestedDocks;
+ if (actions.at(2)->isChecked())
+ opts |= AllowTabbedDocks;
+ if (actions.at(3)->isChecked())
+ opts |= ForceTabbedDocks;
+ if (actions.at(4)->isChecked())
+ opts |= VerticalTabs;
+
+ QMainWindow::setDockOptions(opts);
+}
+
+void MainWindow::saveLayout()
+{
+ QString fileName
+ = QFileDialog::getSaveFileName(this, tr("Save layout"));
+ if (fileName.isEmpty())
+ return;
+ QFile file(fileName);
+ if (!file.open(QFile::WriteOnly)) {
+ QString msg = tr("Failed to open %1\n%2")
+ .arg(fileName)
+ .arg(file.errorString());
+ QMessageBox::warning(this, tr("Error"), msg);
+ return;
+ }
+
+ QByteArray geo_data = saveGeometry();
+ QByteArray layout_data = saveState();
+
+ bool ok = file.putChar((uchar)geo_data.size());
+ if (ok)
+ ok = file.write(geo_data) == geo_data.size();
+ if (ok)
+ ok = file.write(layout_data) == layout_data.size();
+
+ if (!ok) {
+ QString msg = tr("Error writing to %1\n%2")
+ .arg(fileName)
+ .arg(file.errorString());
+ QMessageBox::warning(this, tr("Error"), msg);
+ return;
+ }
+}
+
+void MainWindow::loadLayout()
+{
+ QString fileName
+ = QFileDialog::getOpenFileName(this, tr("Load layout"));
+ if (fileName.isEmpty())
+ return;
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly)) {
+ QString msg = tr("Failed to open %1\n%2")
+ .arg(fileName)
+ .arg(file.errorString());
+ QMessageBox::warning(this, tr("Error"), msg);
+ return;
+ }
+
+ uchar geo_size;
+ QByteArray geo_data;
+ QByteArray layout_data;
+
+ bool ok = file.getChar((char*)&geo_size);
+ if (ok) {
+ geo_data = file.read(geo_size);
+ ok = geo_data.size() == geo_size;
+ }
+ if (ok) {
+ layout_data = file.readAll();
+ ok = layout_data.size() > 0;
+ }
+
+ if (ok)
+ ok = restoreGeometry(geo_data);
+ if (ok)
+ ok = restoreState(layout_data);
+
+ if (!ok) {
+ QString msg = tr("Error reading %1")
+ .arg(fileName);
+ QMessageBox::warning(this, tr("Error"), msg);
+ return;
+ }
+}
+
+QAction *addAction(QMenu *menu, const QString &text, QActionGroup *group, QSignalMapper *mapper,
+ int id)
+{
+ bool first = group->actions().isEmpty();
+ QAction *result = menu->addAction(text);
+ result->setCheckable(true);
+ result->setChecked(first);
+ group->addAction(result);
+ QObject::connect(result, SIGNAL(triggered()), mapper, SLOT(map()));
+ mapper->setMapping(result, id);
+ return result;
+}
+
+void MainWindow::setupDockWidgets(const QMap<QString, QSize> &customSizeHints)
+{
+ mapper = new QSignalMapper(this);
+ connect(mapper, SIGNAL(mapped(int)), this, SLOT(setCorner(int)));
+
+ QMenu *corner_menu = dockWidgetMenu->addMenu(tr("Top left corner"));
+ QActionGroup *group = new QActionGroup(this);
+ group->setExclusive(true);
+ ::addAction(corner_menu, tr("Top dock area"), group, mapper, 0);
+ ::addAction(corner_menu, tr("Left dock area"), group, mapper, 1);
+
+ corner_menu = dockWidgetMenu->addMenu(tr("Top right corner"));
+ group = new QActionGroup(this);
+ group->setExclusive(true);
+ ::addAction(corner_menu, tr("Top dock area"), group, mapper, 2);
+ ::addAction(corner_menu, tr("Right dock area"), group, mapper, 3);
+
+ corner_menu = dockWidgetMenu->addMenu(tr("Bottom left corner"));
+ group = new QActionGroup(this);
+ group->setExclusive(true);
+ ::addAction(corner_menu, tr("Bottom dock area"), group, mapper, 4);
+ ::addAction(corner_menu, tr("Left dock area"), group, mapper, 5);
+
+ corner_menu = dockWidgetMenu->addMenu(tr("Bottom right corner"));
+ group = new QActionGroup(this);
+ group->setExclusive(true);
+ ::addAction(corner_menu, tr("Bottom dock area"), group, mapper, 6);
+ ::addAction(corner_menu, tr("Right dock area"), group, mapper, 7);
+
+ dockWidgetMenu->addSeparator();
+
+ static const struct Set {
+ const char * name;
+ uint flags;
+ Qt::DockWidgetArea area;
+ } sets [] = {
+#ifndef Q_WS_MAC
+ { "Black", 0, Qt::LeftDockWidgetArea },
+#else
+ { "Black", Qt::Drawer, Qt::LeftDockWidgetArea },
+#endif
+ { "White", 0, Qt::RightDockWidgetArea },
+ { "Red", 0, Qt::TopDockWidgetArea },
+ { "Green", 0, Qt::TopDockWidgetArea },
+ { "Blue", 0, Qt::BottomDockWidgetArea },
+ { "Yellow", 0, Qt::BottomDockWidgetArea }
+ };
+ const int setCount = sizeof(sets) / sizeof(Set);
+
+ for (int i = 0; i < setCount; ++i) {
+ ColorSwatch *swatch = new ColorSwatch(tr(sets[i].name), this, Qt::WindowFlags(sets[i].flags));
+ if (i%2)
+ swatch->setWindowIcon(QIcon(QPixmap(":/res/qt.png")));
+ if (qstrcmp(sets[i].name, "Blue") == 0) {
+ BlueTitleBar *titlebar = new BlueTitleBar(swatch);
+ swatch->setTitleBarWidget(titlebar);
+ connect(swatch, SIGNAL(topLevelChanged(bool)), titlebar, SLOT(updateMask()));
+ connect(swatch, SIGNAL(featuresChanged(QDockWidget::DockWidgetFeatures)), titlebar, SLOT(updateMask()));
+
+#ifdef Q_WS_QWS
+ QPalette pal = palette();
+ pal.setBrush(backgroundRole(), QColor(0,0,0,0));
+ swatch->setPalette(pal);
+#endif
+ }
+
+ QString name = QString::fromLatin1(sets[i].name);
+ if (customSizeHints.contains(name))
+ swatch->setCustomSizeHint(customSizeHints.value(name));
+
+ addDockWidget(sets[i].area, swatch);
+ dockWidgetMenu->addMenu(swatch->menu);
+ }
+
+ createDockWidgetAction = new QAction(tr("Add dock widget..."), this);
+ connect(createDockWidgetAction, SIGNAL(triggered()), this, SLOT(createDockWidget()));
+ destroyDockWidgetMenu = new QMenu(tr("Destroy dock widget"), this);
+ destroyDockWidgetMenu->setEnabled(false);
+ connect(destroyDockWidgetMenu, SIGNAL(triggered(QAction*)), this, SLOT(destroyDockWidget(QAction*)));
+
+ dockWidgetMenu->addSeparator();
+ dockWidgetMenu->addAction(createDockWidgetAction);
+ dockWidgetMenu->addMenu(destroyDockWidgetMenu);
+}
+
+void MainWindow::setCorner(int id)
+{
+ switch (id) {
+ case 0:
+ QMainWindow::setCorner(Qt::TopLeftCorner, Qt::TopDockWidgetArea);
+ break;
+ case 1:
+ QMainWindow::setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
+ break;
+ case 2:
+ QMainWindow::setCorner(Qt::TopRightCorner, Qt::TopDockWidgetArea);
+ break;
+ case 3:
+ QMainWindow::setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
+ break;
+ case 4:
+ QMainWindow::setCorner(Qt::BottomLeftCorner, Qt::BottomDockWidgetArea);
+ break;
+ case 5:
+ QMainWindow::setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
+ break;
+ case 6:
+ QMainWindow::setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea);
+ break;
+ case 7:
+ QMainWindow::setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
+ break;
+ }
+}
+
+void MainWindow::showEvent(QShowEvent *event)
+{
+ QMainWindow::showEvent(event);
+}
+
+void MainWindow::switchLayoutDirection()
+{
+ if (layoutDirection() == Qt::LeftToRight)
+ qApp->setLayoutDirection(Qt::RightToLeft);
+ else
+ qApp->setLayoutDirection(Qt::LeftToRight);
+}
+
+class CreateDockWidgetDialog : public QDialog
+{
+public:
+ CreateDockWidgetDialog(QWidget *parent = 0);
+
+ QString objectName() const;
+ Qt::DockWidgetArea location() const;
+
+private:
+ QLineEdit *m_objectName;
+ QComboBox *m_location;
+};
+
+CreateDockWidgetDialog::CreateDockWidgetDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ QGridLayout *layout = new QGridLayout(this);
+
+ layout->addWidget(new QLabel(tr("Object name:")), 0, 0);
+ m_objectName = new QLineEdit;
+ layout->addWidget(m_objectName, 0, 1);
+
+ layout->addWidget(new QLabel(tr("Location:")), 1, 0);
+ m_location = new QComboBox;
+ m_location->setEditable(false);
+ m_location->addItem(tr("Top"));
+ m_location->addItem(tr("Left"));
+ m_location->addItem(tr("Right"));
+ m_location->addItem(tr("Bottom"));
+ m_location->addItem(tr("Restore"));
+ layout->addWidget(m_location, 1, 1);
+
+ QHBoxLayout *buttonLayout = new QHBoxLayout;
+ layout->addLayout(buttonLayout, 2, 0, 1, 2);
+ buttonLayout->addStretch();
+
+ QPushButton *cancelButton = new QPushButton(tr("Cancel"));
+ connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+ buttonLayout->addWidget(cancelButton);
+ QPushButton *okButton = new QPushButton(tr("Ok"));
+ connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
+ buttonLayout->addWidget(okButton);
+
+ okButton->setDefault(true);
+}
+
+QString CreateDockWidgetDialog::objectName() const
+{
+ return m_objectName->text();
+}
+
+Qt::DockWidgetArea CreateDockWidgetDialog::location() const
+{
+ switch (m_location->currentIndex()) {
+ case 0: return Qt::TopDockWidgetArea;
+ case 1: return Qt::LeftDockWidgetArea;
+ case 2: return Qt::RightDockWidgetArea;
+ case 3: return Qt::BottomDockWidgetArea;
+ default:
+ break;
+ }
+ return Qt::NoDockWidgetArea;
+}
+
+void MainWindow::createDockWidget()
+{
+ CreateDockWidgetDialog dialog(this);
+ int ret = dialog.exec();
+ if (ret == QDialog::Rejected)
+ return;
+
+ QDockWidget *dw = new QDockWidget;
+ dw->setObjectName(dialog.objectName());
+ dw->setWindowTitle(dialog.objectName());
+ dw->setWidget(new QTextEdit);
+
+ Qt::DockWidgetArea area = dialog.location();
+ switch (area) {
+ case Qt::LeftDockWidgetArea:
+ case Qt::RightDockWidgetArea:
+ case Qt::TopDockWidgetArea:
+ case Qt::BottomDockWidgetArea:
+ addDockWidget(area, dw);
+ break;
+ default:
+ if (!restoreDockWidget(dw)) {
+ QMessageBox::warning(this, QString(), tr("Failed to restore dock widget"));
+ delete dw;
+ return;
+ }
+ break;
+ }
+
+ extraDockWidgets.append(dw);
+ destroyDockWidgetMenu->setEnabled(true);
+ destroyDockWidgetMenu->addAction(new QAction(dialog.objectName(), this));
+}
+
+void MainWindow::destroyDockWidget(QAction *action)
+{
+ int index = destroyDockWidgetMenu->actions().indexOf(action);
+ delete extraDockWidgets.takeAt(index);
+ destroyDockWidgetMenu->removeAction(action);
+ action->deleteLater();
+
+ if (destroyDockWidgetMenu->isEmpty())
+ destroyDockWidgetMenu->setEnabled(false);
+}
diff --git a/demos/mainwindow/mainwindow.h b/demos/mainwindow/mainwindow.h
new file mode 100644
index 0000000..9c7f620
--- /dev/null
+++ b/demos/mainwindow/mainwindow.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QTextEdit>
+
+class ToolBar;
+QT_FORWARD_DECLARE_CLASS(QMenu)
+QT_FORWARD_DECLARE_CLASS(QSignalMapper)
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+ QTextEdit *center;
+ QList<ToolBar*> toolBars;
+ QMenu *dockWidgetMenu;
+ QMenu *mainWindowMenu;
+ QSignalMapper *mapper;
+ QList<QDockWidget*> extraDockWidgets;
+ QAction *createDockWidgetAction;
+ QMenu *destroyDockWidgetMenu;
+
+public:
+ MainWindow(const QMap<QString, QSize> &customSizeHints,
+ QWidget *parent = 0, Qt::WindowFlags flags = 0);
+
+protected:
+ void showEvent(QShowEvent *event);
+
+public slots:
+ void actionTriggered(QAction *action);
+ void saveLayout();
+ void loadLayout();
+ void setCorner(int id);
+ void switchLayoutDirection();
+ void setDockOptions();
+
+ void createDockWidget();
+ void destroyDockWidget(QAction *action);
+
+private:
+ void setupToolBar();
+ void setupMenuBar();
+ void setupDockWidgets(const QMap<QString, QSize> &customSizeHints);
+};
+
+
+#endif
diff --git a/demos/mainwindow/mainwindow.pro b/demos/mainwindow/mainwindow.pro
new file mode 100644
index 0000000..6e7d784
--- /dev/null
+++ b/demos/mainwindow/mainwindow.pro
@@ -0,0 +1,18 @@
+TEMPLATE = app
+HEADERS += colorswatch.h mainwindow.h toolbar.h
+SOURCES += colorswatch.cpp mainwindow.cpp toolbar.cpp main.cpp
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+RESOURCES += mainwindow.qrc
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/mainwindow
+sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.png *.jpg *.pro
+sources.path = $$[QT_INSTALL_DEMOS]/mainwindow
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
diff --git a/demos/mainwindow/mainwindow.qrc b/demos/mainwindow/mainwindow.qrc
new file mode 100644
index 0000000..47ff22a
--- /dev/null
+++ b/demos/mainwindow/mainwindow.qrc
@@ -0,0 +1,8 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/res">
+ <file>qt.png</file>
+ <file>titlebarLeft.png</file>
+ <file>titlebarCenter.png</file>
+ <file>titlebarRight.png</file>
+</qresource>
+</RCC>
diff --git a/demos/mainwindow/qt.png b/demos/mainwindow/qt.png
new file mode 100644
index 0000000..48fa9fc
--- /dev/null
+++ b/demos/mainwindow/qt.png
Binary files differ
diff --git a/demos/mainwindow/titlebarCenter.png b/demos/mainwindow/titlebarCenter.png
new file mode 100644
index 0000000..5cc1413
--- /dev/null
+++ b/demos/mainwindow/titlebarCenter.png
Binary files differ
diff --git a/demos/mainwindow/titlebarLeft.png b/demos/mainwindow/titlebarLeft.png
new file mode 100644
index 0000000..3151662
--- /dev/null
+++ b/demos/mainwindow/titlebarLeft.png
Binary files differ
diff --git a/demos/mainwindow/titlebarRight.png b/demos/mainwindow/titlebarRight.png
new file mode 100644
index 0000000..a450526
--- /dev/null
+++ b/demos/mainwindow/titlebarRight.png
Binary files differ
diff --git a/demos/mainwindow/toolbar.cpp b/demos/mainwindow/toolbar.cpp
new file mode 100644
index 0000000..9de1348
--- /dev/null
+++ b/demos/mainwindow/toolbar.cpp
@@ -0,0 +1,383 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "toolbar.h"
+
+#include <QMainWindow>
+#include <QMenu>
+#include <QPainter>
+#include <QPainterPath>
+#include <QSpinBox>
+#include <QLabel>
+#include <QToolTip>
+
+#include <stdlib.h>
+
+static QPixmap genIcon(const QSize &iconSize, const QString &, const QColor &color)
+{
+ int w = iconSize.width();
+ int h = iconSize.height();
+
+ QImage image(w, h, QImage::Format_ARGB32_Premultiplied);
+ image.fill(0);
+
+ QPainter p(&image);
+
+ extern void render_qt_text(QPainter *, int, int, const QColor &);
+ render_qt_text(&p, w, h, color);
+
+ return QPixmap::fromImage(image, Qt::DiffuseDither | Qt::DiffuseAlphaDither);
+}
+
+static QPixmap genIcon(const QSize &iconSize, int number, const QColor &color)
+{ return genIcon(iconSize, QString::number(number), color); }
+
+ToolBar::ToolBar(const QString &title, QWidget *parent)
+ : QToolBar(parent), spinbox(0), spinboxAction(0)
+{
+ tip = 0;
+ setWindowTitle(title);
+ setObjectName(title);
+
+ setIconSize(QSize(32, 32));
+
+ QColor bg(palette().background().color());
+ menu = new QMenu("One", this);
+ menu->setIcon(genIcon(iconSize(), 1, Qt::black));
+ menu->addAction(genIcon(iconSize(), "A", Qt::blue), "A");
+ menu->addAction(genIcon(iconSize(), "B", Qt::blue), "B");
+ menu->addAction(genIcon(iconSize(), "C", Qt::blue), "C");
+ addAction(menu->menuAction());
+
+ QAction *two = addAction(genIcon(iconSize(), 2, Qt::white), "Two");
+ QFont boldFont;
+ boldFont.setBold(true);
+ two->setFont(boldFont);
+
+ addAction(genIcon(iconSize(), 3, Qt::red), "Three");
+ addAction(genIcon(iconSize(), 4, Qt::green), "Four");
+ addAction(genIcon(iconSize(), 5, Qt::blue), "Five");
+ addAction(genIcon(iconSize(), 6, Qt::yellow), "Six");
+ orderAction = new QAction(this);
+ orderAction->setText(tr("Order Items in Tool Bar"));
+ connect(orderAction, SIGNAL(triggered()), SLOT(order()));
+
+ randomizeAction = new QAction(this);
+ randomizeAction->setText(tr("Randomize Items in Tool Bar"));
+ connect(randomizeAction, SIGNAL(triggered()), SLOT(randomize()));
+
+ addSpinBoxAction = new QAction(this);
+ addSpinBoxAction->setText(tr("Add Spin Box"));
+ connect(addSpinBoxAction, SIGNAL(triggered()), SLOT(addSpinBox()));
+
+ removeSpinBoxAction = new QAction(this);
+ removeSpinBoxAction->setText(tr("Remove Spin Box"));
+ removeSpinBoxAction->setEnabled(false);
+ connect(removeSpinBoxAction, SIGNAL(triggered()), SLOT(removeSpinBox()));
+
+ movableAction = new QAction(tr("Movable"), this);
+ movableAction->setCheckable(true);
+ connect(movableAction, SIGNAL(triggered(bool)), SLOT(changeMovable(bool)));
+
+ allowedAreasActions = new QActionGroup(this);
+ allowedAreasActions->setExclusive(false);
+
+ allowLeftAction = new QAction(tr("Allow on Left"), this);
+ allowLeftAction->setCheckable(true);
+ connect(allowLeftAction, SIGNAL(triggered(bool)), SLOT(allowLeft(bool)));
+
+ allowRightAction = new QAction(tr("Allow on Right"), this);
+ allowRightAction->setCheckable(true);
+ connect(allowRightAction, SIGNAL(triggered(bool)), SLOT(allowRight(bool)));
+
+ allowTopAction = new QAction(tr("Allow on Top"), this);
+ allowTopAction->setCheckable(true);
+ connect(allowTopAction, SIGNAL(triggered(bool)), SLOT(allowTop(bool)));
+
+ allowBottomAction = new QAction(tr("Allow on Bottom"), this);
+ allowBottomAction->setCheckable(true);
+ connect(allowBottomAction, SIGNAL(triggered(bool)), SLOT(allowBottom(bool)));
+
+ allowedAreasActions->addAction(allowLeftAction);
+ allowedAreasActions->addAction(allowRightAction);
+ allowedAreasActions->addAction(allowTopAction);
+ allowedAreasActions->addAction(allowBottomAction);
+
+ areaActions = new QActionGroup(this);
+ areaActions->setExclusive(true);
+
+ leftAction = new QAction(tr("Place on Left") , this);
+ leftAction->setCheckable(true);
+ connect(leftAction, SIGNAL(triggered(bool)), SLOT(placeLeft(bool)));
+
+ rightAction = new QAction(tr("Place on Right") , this);
+ rightAction->setCheckable(true);
+ connect(rightAction, SIGNAL(triggered(bool)), SLOT(placeRight(bool)));
+
+ topAction = new QAction(tr("Place on Top") , this);
+ topAction->setCheckable(true);
+ connect(topAction, SIGNAL(triggered(bool)), SLOT(placeTop(bool)));
+
+ bottomAction = new QAction(tr("Place on Bottom") , this);
+ bottomAction->setCheckable(true);
+ connect(bottomAction, SIGNAL(triggered(bool)), SLOT(placeBottom(bool)));
+
+ areaActions->addAction(leftAction);
+ areaActions->addAction(rightAction);
+ areaActions->addAction(topAction);
+ areaActions->addAction(bottomAction);
+
+ toolBarBreakAction = new QAction(tr("Insert break"), this);
+ connect(toolBarBreakAction, SIGNAL(triggered(bool)), this, SLOT(insertToolBarBreak()));
+
+ connect(movableAction, SIGNAL(triggered(bool)), areaActions, SLOT(setEnabled(bool)));
+
+ connect(movableAction, SIGNAL(triggered(bool)), allowedAreasActions, SLOT(setEnabled(bool)));
+
+ menu = new QMenu(title, this);
+ menu->addAction(toggleViewAction());
+ menu->addSeparator();
+ menu->addAction(orderAction);
+ menu->addAction(randomizeAction);
+ menu->addSeparator();
+ menu->addAction(addSpinBoxAction);
+ menu->addAction(removeSpinBoxAction);
+ menu->addSeparator();
+ menu->addAction(movableAction);
+ menu->addSeparator();
+ menu->addActions(allowedAreasActions->actions());
+ menu->addSeparator();
+ menu->addActions(areaActions->actions());
+ menu->addSeparator();
+ menu->addAction(toolBarBreakAction);
+
+ connect(menu, SIGNAL(aboutToShow()), this, SLOT(updateMenu()));
+
+ randomize();
+}
+
+void ToolBar::updateMenu()
+{
+ QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
+ Q_ASSERT(mainWindow != 0);
+
+ const Qt::ToolBarArea area = mainWindow->toolBarArea(this);
+ const Qt::ToolBarAreas areas = allowedAreas();
+
+ movableAction->setChecked(isMovable());
+
+ allowLeftAction->setChecked(isAreaAllowed(Qt::LeftToolBarArea));
+ allowRightAction->setChecked(isAreaAllowed(Qt::RightToolBarArea));
+ allowTopAction->setChecked(isAreaAllowed(Qt::TopToolBarArea));
+ allowBottomAction->setChecked(isAreaAllowed(Qt::BottomToolBarArea));
+
+ if (allowedAreasActions->isEnabled()) {
+ allowLeftAction->setEnabled(area != Qt::LeftToolBarArea);
+ allowRightAction->setEnabled(area != Qt::RightToolBarArea);
+ allowTopAction->setEnabled(area != Qt::TopToolBarArea);
+ allowBottomAction->setEnabled(area != Qt::BottomToolBarArea);
+ }
+
+ leftAction->setChecked(area == Qt::LeftToolBarArea);
+ rightAction->setChecked(area == Qt::RightToolBarArea);
+ topAction->setChecked(area == Qt::TopToolBarArea);
+ bottomAction->setChecked(area == Qt::BottomToolBarArea);
+
+ if (areaActions->isEnabled()) {
+ leftAction->setEnabled(areas & Qt::LeftToolBarArea);
+ rightAction->setEnabled(areas & Qt::RightToolBarArea);
+ topAction->setEnabled(areas & Qt::TopToolBarArea);
+ bottomAction->setEnabled(areas & Qt::BottomToolBarArea);
+ }
+}
+
+void ToolBar::order()
+{
+ QList<QAction *> ordered, actions1 = actions(),
+ actions2 = qFindChildren<QAction *>(this);
+ while (!actions2.isEmpty()) {
+ QAction *action = actions2.takeFirst();
+ if (!actions1.contains(action))
+ continue;
+ actions1.removeAll(action);
+ ordered.append(action);
+ }
+
+ clear();
+ addActions(ordered);
+
+ orderAction->setEnabled(false);
+}
+
+void ToolBar::randomize()
+{
+ QList<QAction *> randomized, actions = this->actions();
+ while (!actions.isEmpty()) {
+ QAction *action = actions.takeAt(rand() % actions.size());
+ randomized.append(action);
+ }
+ clear();
+ addActions(randomized);
+
+ orderAction->setEnabled(true);
+}
+
+void ToolBar::addSpinBox()
+{
+ if (!spinbox) {
+ spinbox = new QSpinBox(this);
+ }
+ if (!spinboxAction)
+ spinboxAction = addWidget(spinbox);
+ else
+ addAction(spinboxAction);
+
+ addSpinBoxAction->setEnabled(false);
+ removeSpinBoxAction->setEnabled(true);
+}
+
+void ToolBar::removeSpinBox()
+{
+ if (spinboxAction)
+ removeAction(spinboxAction);
+
+ addSpinBoxAction->setEnabled(true);
+ removeSpinBoxAction->setEnabled(false);
+}
+
+void ToolBar::allow(Qt::ToolBarArea area, bool a)
+{
+ Qt::ToolBarAreas areas = allowedAreas();
+ areas = a ? areas | area : areas & ~area;
+ setAllowedAreas(areas);
+
+ if (areaActions->isEnabled()) {
+ leftAction->setEnabled(areas & Qt::LeftToolBarArea);
+ rightAction->setEnabled(areas & Qt::RightToolBarArea);
+ topAction->setEnabled(areas & Qt::TopToolBarArea);
+ bottomAction->setEnabled(areas & Qt::BottomToolBarArea);
+ }
+}
+
+void ToolBar::place(Qt::ToolBarArea area, bool p)
+{
+ if (!p)
+ return;
+
+ QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
+ Q_ASSERT(mainWindow != 0);
+
+ mainWindow->addToolBar(area, this);
+
+ if (allowedAreasActions->isEnabled()) {
+ allowLeftAction->setEnabled(area != Qt::LeftToolBarArea);
+ allowRightAction->setEnabled(area != Qt::RightToolBarArea);
+ allowTopAction->setEnabled(area != Qt::TopToolBarArea);
+ allowBottomAction->setEnabled(area != Qt::BottomToolBarArea);
+ }
+}
+
+void ToolBar::changeMovable(bool movable)
+{ setMovable(movable); }
+
+void ToolBar::allowLeft(bool a)
+{ allow(Qt::LeftToolBarArea, a); }
+
+void ToolBar::allowRight(bool a)
+{ allow(Qt::RightToolBarArea, a); }
+
+void ToolBar::allowTop(bool a)
+{ allow(Qt::TopToolBarArea, a); }
+
+void ToolBar::allowBottom(bool a)
+{ allow(Qt::BottomToolBarArea, a); }
+
+void ToolBar::placeLeft(bool p)
+{ place(Qt::LeftToolBarArea, p); }
+
+void ToolBar::placeRight(bool p)
+{ place(Qt::RightToolBarArea, p); }
+
+void ToolBar::placeTop(bool p)
+{ place(Qt::TopToolBarArea, p); }
+
+void ToolBar::placeBottom(bool p)
+{ place(Qt::BottomToolBarArea, p); }
+
+void ToolBar::insertToolBarBreak()
+{
+ QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
+ Q_ASSERT(mainWindow != 0);
+
+ mainWindow->insertToolBarBreak(this);
+}
+
+void ToolBar::enterEvent(QEvent*)
+{
+/*
+ These labels on top of toolbars look darn ugly
+
+ if (tip == 0) {
+ tip = new QLabel(windowTitle(), this);
+ QPalette pal = tip->palette();
+ QColor c = Qt::black;
+ c.setAlpha(100);
+ pal.setColor(QPalette::Window, c);
+ pal.setColor(QPalette::Foreground, Qt::white);
+ tip->setPalette(pal);
+ tip->setAutoFillBackground(true);
+ tip->setMargin(3);
+ tip->setText(windowTitle());
+ }
+ QPoint c = rect().center();
+ QSize hint = tip->sizeHint();
+ tip->setGeometry(c.x() - hint.width()/2, c.y() - hint.height()/2,
+ hint.width(), hint.height());
+
+ tip->show();
+*/
+}
+
+void ToolBar::leaveEvent(QEvent*)
+{
+ if (tip != 0)
+ tip->hide();
+}
diff --git a/demos/mainwindow/toolbar.h b/demos/mainwindow/toolbar.h
new file mode 100644
index 0000000..a9b9af2
--- /dev/null
+++ b/demos/mainwindow/toolbar.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TOOLBAR_H
+#define TOOLBAR_H
+
+#include <QToolBar>
+
+QT_FORWARD_DECLARE_CLASS(QAction)
+QT_FORWARD_DECLARE_CLASS(QActionGroup)
+QT_FORWARD_DECLARE_CLASS(QMenu)
+QT_FORWARD_DECLARE_CLASS(QSpinBox)
+QT_FORWARD_DECLARE_CLASS(QLabel)
+
+class ToolBar : public QToolBar
+{
+ Q_OBJECT
+
+ QSpinBox *spinbox;
+ QAction *spinboxAction;
+
+ QAction *orderAction;
+ QAction *randomizeAction;
+ QAction *addSpinBoxAction;
+ QAction *removeSpinBoxAction;
+
+ QAction *movableAction;
+
+ QActionGroup *allowedAreasActions;
+ QAction *allowLeftAction;
+ QAction *allowRightAction;
+ QAction *allowTopAction;
+ QAction *allowBottomAction;
+
+ QActionGroup *areaActions;
+ QAction *leftAction;
+ QAction *rightAction;
+ QAction *topAction;
+ QAction *bottomAction;
+
+ QAction *toolBarBreakAction;
+
+public:
+ ToolBar(const QString &title, QWidget *parent);
+
+ QMenu *menu;
+
+protected:
+ void enterEvent(QEvent*);
+ void leaveEvent(QEvent*);
+
+private:
+ void allow(Qt::ToolBarArea area, bool allow);
+ void place(Qt::ToolBarArea area, bool place);
+ QLabel *tip;
+
+private slots:
+ void order();
+ void randomize();
+ void addSpinBox();
+ void removeSpinBox();
+
+ void changeMovable(bool movable);
+
+ void allowLeft(bool a);
+ void allowRight(bool a);
+ void allowTop(bool a);
+ void allowBottom(bool a);
+
+ void placeLeft(bool p);
+ void placeRight(bool p);
+ void placeTop(bool p);
+ void placeBottom(bool p);
+
+ void updateMenu();
+ void insertToolBarBreak();
+
+};
+
+#endif
diff --git a/demos/mediaplayer/images/screen.png b/demos/mediaplayer/images/screen.png
new file mode 100644
index 0000000..a15df92
--- /dev/null
+++ b/demos/mediaplayer/images/screen.png
Binary files differ
diff --git a/demos/mediaplayer/main.cpp b/demos/mediaplayer/main.cpp
new file mode 100644
index 0000000..279a6c7
--- /dev/null
+++ b/demos/mediaplayer/main.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+***************************************************************************/
+
+#include <QtGui>
+#include "mediaplayer.h"
+
+int main (int argc, char *argv[])
+{
+ Q_INIT_RESOURCE(mediaplayer);
+ QApplication app(argc, argv);
+ app.setApplicationName("Media Player");
+ app.setOrganizationName("Trolltech");
+ app.setQuitOnLastWindowClosed(true);
+
+ QString fileString = app.arguments().value(1);
+ MediaPlayer player(fileString);
+ player.show();
+
+ return app.exec();
+}
+
diff --git a/demos/mediaplayer/mediaplayer.cpp b/demos/mediaplayer/mediaplayer.cpp
new file mode 100644
index 0000000..5f5a5dc
--- /dev/null
+++ b/demos/mediaplayer/mediaplayer.cpp
@@ -0,0 +1,840 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+***************************************************************************/
+
+#include <QtGui>
+
+#define SLIDER_RANGE 8
+
+#include "mediaplayer.h"
+#include "ui_settings.h"
+
+
+class MediaVideoWidget : public Phonon::VideoWidget
+{
+public:
+ MediaVideoWidget(MediaPlayer *player, QWidget *parent = 0) :
+ Phonon::VideoWidget(parent), m_player(player), m_action(this)
+ {
+ m_action.setCheckable(true);
+ m_action.setChecked(false);
+ m_action.setShortcut(QKeySequence( Qt::AltModifier + Qt::Key_Return));
+ m_action.setShortcutContext(Qt::WindowShortcut);
+ connect(&m_action, SIGNAL(toggled(bool)), SLOT(setFullScreen(bool)));
+ addAction(&m_action);
+ setAcceptDrops(true);
+ }
+
+protected:
+ void mouseDoubleClickEvent(QMouseEvent *e)
+ {
+ Phonon::VideoWidget::mouseDoubleClickEvent(e);
+ setFullScreen(!isFullScreen());
+ }
+
+ void keyPressEvent(QKeyEvent *e)
+ {
+ if (e->key() == Qt::Key_Space && !e->modifiers()) {
+ m_player->playPause();
+ e->accept();
+ return;
+ } else if (e->key() == Qt::Key_Escape && !e->modifiers()) {
+ setFullScreen(false);
+ e->accept();
+ return;
+ }
+ Phonon::VideoWidget::keyPressEvent(e);
+ }
+
+ bool event(QEvent *e)
+ {
+ switch(e->type())
+ {
+ case QEvent::Close:
+ //we just ignore the cose events on the video widget
+ //this prevents ALT+F4 from having an effect in fullscreen mode
+ e->ignore();
+ return true;
+ case QEvent::MouseMove:
+#ifndef QT_NO_CURSOR
+ unsetCursor();
+#endif
+ //fall through
+ case QEvent::WindowStateChange:
+ {
+ //we just update the state of the checkbox, in case it wasn't already
+ m_action.setChecked(windowState() & Qt::WindowFullScreen);
+ const Qt::WindowFlags flags = m_player->windowFlags();
+ if (windowState() & Qt::WindowFullScreen) {
+ m_timer.start(1000, this);
+ } else {
+ m_timer.stop();
+#ifndef QT_NO_CURSOR
+ unsetCursor();
+#endif
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return Phonon::VideoWidget::event(e);
+ }
+
+ void timerEvent(QTimerEvent *e)
+ {
+ if (e->timerId() == m_timer.timerId()) {
+ //let's store the cursor shape
+#ifndef QT_NO_CURSOR
+ setCursor(Qt::BlankCursor);
+#endif
+ }
+ Phonon::VideoWidget::timerEvent(e);
+ }
+
+ void dropEvent(QDropEvent *e)
+ {
+ m_player->handleDrop(e);
+ }
+
+ void dragEnterEvent(QDragEnterEvent *e) {
+ if (e->mimeData()->hasUrls())
+ e->acceptProposedAction();
+ }
+
+private:
+ MediaPlayer *m_player;
+ QBasicTimer m_timer;
+ QAction m_action;
+};
+
+
+MediaPlayer::MediaPlayer(const QString &filePath) :
+ playButton(0), nextEffect(0), settingsDialog(0), ui(0),
+ m_AudioOutput(Phonon::VideoCategory),
+ m_videoWidget(new MediaVideoWidget(this))
+{
+ setWindowTitle(tr("Media Player"));
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ m_videoWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ QSize buttonSize(34, 28);
+
+ QPushButton *openButton = new QPushButton(this);
+
+ openButton->setIcon(style()->standardIcon(QStyle::SP_DialogOpenButton));
+ QPalette bpal;
+ QColor arrowcolor = bpal.buttonText().color();
+ if (arrowcolor == Qt::black)
+ arrowcolor = QColor(80, 80, 80);
+ bpal.setBrush(QPalette::ButtonText, arrowcolor);
+ openButton->setPalette(bpal);
+
+ rewindButton = new QPushButton(this);
+ rewindButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipBackward));
+
+ forwardButton = new QPushButton(this);
+ forwardButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipForward));
+ forwardButton->setEnabled(false);
+
+ playButton = new QPushButton(this);
+ playIcon = style()->standardIcon(QStyle::SP_MediaPlay);
+ pauseIcon = style()->standardIcon(QStyle::SP_MediaPause);
+ playButton->setIcon(playIcon);
+
+ slider = new Phonon::SeekSlider(this);
+ slider->setMediaObject(&m_MediaObject);
+ volume = new Phonon::VolumeSlider(&m_AudioOutput);
+
+ QVBoxLayout *vLayout = new QVBoxLayout(this);
+ vLayout->setContentsMargins(8, 8, 8, 8);
+
+ QHBoxLayout *layout = new QHBoxLayout();
+
+ info = new QLabel(this);
+ info->setMinimumHeight(70);
+ info->setAcceptDrops(false);
+ info->setMargin(2);
+ info->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
+ info->setLineWidth(2);
+ info->setAutoFillBackground(true);
+
+ QPalette palette;
+ palette.setBrush(QPalette::WindowText, Qt::white);
+#ifndef Q_WS_MAC
+ openButton->setMinimumSize(54, buttonSize.height());
+ rewindButton->setMinimumSize(buttonSize);
+ forwardButton->setMinimumSize(buttonSize);
+ playButton->setMinimumSize(buttonSize);
+#endif
+ info->setStyleSheet("border-image:url(:/images/screen.png) ; border-width:3px");
+ info->setPalette(palette);
+ info->setText(tr("<center>No media</center>"));
+
+ volume->setFixedWidth(120);
+
+ layout->addWidget(openButton);
+ layout->addWidget(rewindButton);
+ layout->addWidget(playButton);
+ layout->addWidget(forwardButton);
+
+ layout->addStretch();
+ layout->addWidget(volume);
+
+ vLayout->addWidget(info);
+ initVideoWindow();
+ vLayout->addWidget(&m_videoWindow);
+ QVBoxLayout *buttonPanelLayout = new QVBoxLayout();
+ m_videoWindow.hide();
+ buttonPanelLayout->addLayout(layout);
+
+ timeLabel = new QLabel(this);
+ progressLabel = new QLabel(this);
+ QWidget *sliderPanel = new QWidget(this);
+ QHBoxLayout *sliderLayout = new QHBoxLayout();
+ sliderLayout->addWidget(slider);
+ sliderLayout->addWidget(timeLabel);
+ sliderLayout->addWidget(progressLabel);
+ sliderLayout->setContentsMargins(0, 0, 0, 0);
+ sliderPanel->setLayout(sliderLayout);
+
+ buttonPanelLayout->addWidget(sliderPanel);
+ buttonPanelLayout->setContentsMargins(0, 0, 0, 0);
+#ifdef Q_OS_MAC
+ layout->setSpacing(4);
+ buttonPanelLayout->setSpacing(0);
+ info->setMinimumHeight(100);
+ info->setFont(QFont("verdana", 15));
+ // QStyle *flatButtonStyle = new QWindowsStyle;
+ openButton->setFocusPolicy(Qt::NoFocus);
+ // openButton->setStyle(flatButtonStyle);
+ // playButton->setStyle(flatButtonStyle);
+ // rewindButton->setStyle(flatButtonStyle);
+ // forwardButton->setStyle(flatButtonStyle);
+ #endif
+ QWidget *buttonPanelWidget = new QWidget(this);
+ buttonPanelWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ buttonPanelWidget->setLayout(buttonPanelLayout);
+ vLayout->addWidget(buttonPanelWidget);
+
+ QHBoxLayout *labelLayout = new QHBoxLayout();
+
+ vLayout->addLayout(labelLayout);
+ setLayout(vLayout);
+
+ // Create menu bar:
+ fileMenu = new QMenu(this);
+ QAction *openFileAction = fileMenu->addAction(tr("Open &File..."));
+ QAction *openUrlAction = fileMenu->addAction(tr("Open &Location..."));
+
+ fileMenu->addSeparator();
+ QMenu *aspectMenu = fileMenu->addMenu(tr("&Aspect ratio"));
+ QActionGroup *aspectGroup = new QActionGroup(aspectMenu);
+ connect(aspectGroup, SIGNAL(triggered(QAction *)), this, SLOT(aspectChanged(QAction *)));
+ aspectGroup->setExclusive(true);
+ QAction *aspectActionAuto = aspectMenu->addAction(tr("Auto"));
+ aspectActionAuto->setCheckable(true);
+ aspectActionAuto->setChecked(true);
+ aspectGroup->addAction(aspectActionAuto);
+ QAction *aspectActionScale = aspectMenu->addAction(tr("Scale"));
+ aspectActionScale->setCheckable(true);
+ aspectGroup->addAction(aspectActionScale);
+ QAction *aspectAction16_9 = aspectMenu->addAction(tr("16/9"));
+ aspectAction16_9->setCheckable(true);
+ aspectGroup->addAction(aspectAction16_9);
+ QAction *aspectAction4_3 = aspectMenu->addAction(tr("4/3"));
+ aspectAction4_3->setCheckable(true);
+ aspectGroup->addAction(aspectAction4_3);
+
+ QMenu *scaleMenu = fileMenu->addMenu(tr("&Scale mode"));
+ QActionGroup *scaleGroup = new QActionGroup(scaleMenu);
+ connect(scaleGroup, SIGNAL(triggered(QAction *)), this, SLOT(scaleChanged(QAction *)));
+ scaleGroup->setExclusive(true);
+ QAction *scaleActionFit = scaleMenu->addAction(tr("Fit in view"));
+ scaleActionFit->setCheckable(true);
+ scaleActionFit->setChecked(true);
+ scaleGroup->addAction(scaleActionFit);
+ QAction *scaleActionCrop = scaleMenu->addAction(tr("Scale and crop"));
+ scaleActionCrop->setCheckable(true);
+ scaleGroup->addAction(scaleActionCrop);
+
+ fileMenu->addSeparator();
+ QAction *settingsAction = fileMenu->addAction(tr("&Settings..."));
+
+ // Setup signal connections:
+ connect(rewindButton, SIGNAL(clicked()), this, SLOT(rewind()));
+ //connect(openButton, SIGNAL(clicked()), this, SLOT(openFile()));
+ openButton->setMenu(fileMenu);
+
+ connect(playButton, SIGNAL(clicked()), this, SLOT(playPause()));
+ connect(forwardButton, SIGNAL(clicked()), this, SLOT(forward()));
+ //connect(openButton, SIGNAL(clicked()), this, SLOT(openFile()));
+ connect(settingsAction, SIGNAL(triggered(bool)), this, SLOT(showSettingsDialog()));
+ connect(openUrlAction, SIGNAL(triggered(bool)), this, SLOT(openUrl()));
+ connect(openFileAction, SIGNAL(triggered(bool)), this, SLOT(openFile()));
+
+ connect(m_videoWidget, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(showContextMenu(const QPoint &)));
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(showContextMenu(const QPoint &)));
+ connect(&m_MediaObject, SIGNAL(metaDataChanged()), this, SLOT(updateInfo()));
+ connect(&m_MediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(updateTime()));
+ connect(&m_MediaObject, SIGNAL(tick(qint64)), this, SLOT(updateTime()));
+ connect(&m_MediaObject, SIGNAL(finished()), this, SLOT(finished()));
+ connect(&m_MediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged(Phonon::State, Phonon::State)));
+ connect(&m_MediaObject, SIGNAL(bufferStatus(int)), this, SLOT(bufferStatus(int)));
+
+ rewindButton->setEnabled(false);
+ playButton->setEnabled(false);
+ setAcceptDrops(true);
+
+ m_audioOutputPath = Phonon::createPath(&m_MediaObject, &m_AudioOutput);
+ Phonon::createPath(&m_MediaObject, m_videoWidget);
+
+ if (!filePath.isEmpty())
+ setFile(filePath);
+ resize(minimumSizeHint());
+}
+
+void MediaPlayer::stateChanged(Phonon::State newstate, Phonon::State oldstate)
+{
+ Q_UNUSED(oldstate);
+
+ if (oldstate == Phonon::LoadingState) {
+ m_videoWindow.setVisible(m_MediaObject.hasVideo());
+ info->setVisible(!m_MediaObject.hasVideo());
+ QRect videoHintRect = QRect(QPoint(0, 0), m_videoWindow.sizeHint());
+ QRect newVideoRect = QApplication::desktop()->screenGeometry().intersected(videoHintRect);
+ if (m_MediaObject.hasVideo()){
+ // Flush event que so that sizeHint takes the
+ // recently shown/hidden m_videoWindow into account:
+ qApp->processEvents();
+ resize(sizeHint());
+ } else
+ resize(minimumSize());
+ }
+
+ switch (newstate) {
+ case Phonon::ErrorState:
+ QMessageBox::warning(this, "Phonon Mediaplayer", m_MediaObject.errorString(), QMessageBox::Close);
+ if (m_MediaObject.errorType() == Phonon::FatalError) {
+ playButton->setEnabled(false);
+ rewindButton->setEnabled(false);
+ } else {
+ m_MediaObject.pause();
+ }
+ break;
+ case Phonon::PausedState:
+ case Phonon::StoppedState:
+ playButton->setIcon(playIcon);
+ if (m_MediaObject.currentSource().type() != Phonon::MediaSource::Invalid){
+ playButton->setEnabled(true);
+ rewindButton->setEnabled(true);
+ } else {
+ playButton->setEnabled(false);
+ rewindButton->setEnabled(false);
+ }
+ break;
+ case Phonon::PlayingState:
+ playButton->setEnabled(true);
+ playButton->setIcon(pauseIcon);
+ if (m_MediaObject.hasVideo())
+ m_videoWindow.show();
+ // Fall through
+ case Phonon::BufferingState:
+ rewindButton->setEnabled(true);
+ break;
+ case Phonon::LoadingState:
+ rewindButton->setEnabled(false);
+ break;
+ }
+
+}
+
+void MediaPlayer::initSettingsDialog()
+{
+ settingsDialog = new QDialog(this);
+ ui = new Ui_settings();
+ ui->setupUi(settingsDialog);
+
+ connect(ui->brightnessSlider, SIGNAL(valueChanged(int)), this, SLOT(setBrightness(int)));
+ connect(ui->hueSlider, SIGNAL(valueChanged(int)), this, SLOT(setHue(int)));
+ connect(ui->saturationSlider, SIGNAL(valueChanged(int)), this, SLOT(setSaturation(int)));
+ connect(ui->contrastSlider , SIGNAL(valueChanged(int)), this, SLOT(setContrast(int)));
+ connect(ui->aspectCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setAspect(int)));
+ connect(ui->scalemodeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setScale(int)));
+
+ ui->brightnessSlider->setValue(int(m_videoWidget->brightness() * SLIDER_RANGE));
+ ui->hueSlider->setValue(int(m_videoWidget->hue() * SLIDER_RANGE));
+ ui->saturationSlider->setValue(int(m_videoWidget->saturation() * SLIDER_RANGE));
+ ui->contrastSlider->setValue(int(m_videoWidget->contrast() * SLIDER_RANGE));
+ ui->aspectCombo->setCurrentIndex(m_videoWidget->aspectRatio());
+ ui->scalemodeCombo->setCurrentIndex(m_videoWidget->scaleMode());
+ connect(ui->effectButton, SIGNAL(clicked()), this, SLOT(configureEffect()));
+
+#ifdef Q_WS_X11
+ //Cross fading is not currently implemented in the GStreamer backend
+ ui->crossFadeSlider->setVisible(false);
+ ui->crossFadeLabel->setVisible(false);
+ ui->crossFadeLabel1->setVisible(false);
+ ui->crossFadeLabel2->setVisible(false);
+ ui->crossFadeLabel3->setVisible(false);
+#endif
+ ui->crossFadeSlider->setValue((int)(2 * m_MediaObject.transitionTime() / 1000.0f));
+
+ // Insert audio devices:
+ QList<Phonon::AudioOutputDevice> devices = Phonon::BackendCapabilities::availableAudioOutputDevices();
+ for (int i=0; i<devices.size(); i++){
+ QString itemText = devices[i].name();
+ if (!devices[i].description().isEmpty()) {
+ itemText += QString::fromLatin1(" (%1)").arg(devices[i].description());
+ }
+ ui->deviceCombo->addItem(itemText);
+ if (devices[i] == m_AudioOutput.outputDevice())
+ ui->deviceCombo->setCurrentIndex(i);
+ }
+
+ // Insert audio effects:
+ ui->audioEffectsCombo->addItem(tr("<no effect>"));
+ QList<Phonon::Effect *> currEffects = m_audioOutputPath.effects();
+ Phonon::Effect *currEffect = currEffects.size() ? currEffects[0] : 0;
+ QList<Phonon::EffectDescription> availableEffects = Phonon::BackendCapabilities::availableAudioEffects();
+ for (int i=0; i<availableEffects.size(); i++){
+ ui->audioEffectsCombo->addItem(availableEffects[i].name());
+ if (currEffect && availableEffects[i] == currEffect->description())
+ ui->audioEffectsCombo->setCurrentIndex(i+1);
+ }
+ connect(ui->audioEffectsCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(effectChanged()));
+
+}
+
+void MediaPlayer::effectChanged()
+{
+ int currentIndex = ui->audioEffectsCombo->currentIndex();
+ if (currentIndex) {
+ QList<Phonon::EffectDescription> availableEffects = Phonon::BackendCapabilities::availableAudioEffects();
+ Phonon::EffectDescription chosenEffect = availableEffects[currentIndex - 1];
+
+ QList<Phonon::Effect *> currEffects = m_audioOutputPath.effects();
+ Phonon::Effect *currentEffect = currEffects.size() ? currEffects[0] : 0;
+
+ // Deleting the running effect will stop playback, it is deleted when removed from path
+ if (nextEffect && !(currentEffect && (currentEffect->description().name() == nextEffect->description().name())))
+ delete nextEffect;
+
+ nextEffect = new Phonon::Effect(chosenEffect);
+ }
+ ui->effectButton->setEnabled(currentIndex);
+}
+
+void MediaPlayer::showSettingsDialog()
+{
+ if (!settingsDialog)
+ initSettingsDialog();
+
+ float oldBrightness = m_videoWidget->brightness();
+ float oldHue = m_videoWidget->hue();
+ float oldSaturation = m_videoWidget->saturation();
+ float oldContrast = m_videoWidget->contrast();
+ Phonon::VideoWidget::AspectRatio oldAspect = m_videoWidget->aspectRatio();
+ Phonon::VideoWidget::ScaleMode oldScale = m_videoWidget->scaleMode();
+ int currentEffect = ui->audioEffectsCombo->currentIndex();
+ settingsDialog->exec();
+
+ if (settingsDialog->result() == QDialog::Accepted){
+ m_MediaObject.setTransitionTime((int)(1000 * float(ui->crossFadeSlider->value()) / 2.0f));
+ QList<Phonon::AudioOutputDevice> devices = Phonon::BackendCapabilities::availableAudioOutputDevices();
+ m_AudioOutput.setOutputDevice(devices[ui->deviceCombo->currentIndex()]);
+ QList<Phonon::Effect *> currEffects = m_audioOutputPath.effects();
+ QList<Phonon::EffectDescription> availableEffects = Phonon::BackendCapabilities::availableAudioEffects();
+
+ if (ui->audioEffectsCombo->currentIndex() > 0){
+ Phonon::Effect *currentEffect = currEffects.size() ? currEffects[0] : 0;
+ if (!currentEffect || currentEffect->description() != nextEffect->description()){
+ foreach(Phonon::Effect *effect, currEffects) {
+ m_audioOutputPath.removeEffect(effect);
+ delete effect;
+ }
+ m_audioOutputPath.insertEffect(nextEffect);
+ }
+ } else {
+ foreach(Phonon::Effect *effect, currEffects) {
+ m_audioOutputPath.removeEffect(effect);
+ delete effect;
+ nextEffect = 0;
+ }
+ }
+ } else {
+ // Restore previous settings
+ m_videoWidget->setBrightness(oldBrightness);
+ m_videoWidget->setSaturation(oldSaturation);
+ m_videoWidget->setHue(oldHue);
+ m_videoWidget->setContrast(oldContrast);
+ m_videoWidget->setAspectRatio(oldAspect);
+ m_videoWidget->setScaleMode(oldScale);
+ ui->audioEffectsCombo->setCurrentIndex(currentEffect);
+ }
+}
+
+void MediaPlayer::initVideoWindow()
+{
+ QVBoxLayout *videoLayout = new QVBoxLayout();
+ videoLayout->addWidget(m_videoWidget);
+ videoLayout->setContentsMargins(0, 0, 0, 0);
+ m_videoWindow.setLayout(videoLayout);
+ m_videoWindow.setMinimumSize(100, 100);
+}
+
+
+void MediaPlayer::configureEffect()
+{
+ if (!nextEffect)
+ return;
+
+
+ QList<Phonon::Effect *> currEffects = m_audioOutputPath.effects();
+ const QList<Phonon::EffectDescription> availableEffects = Phonon::BackendCapabilities::availableAudioEffects();
+ if (ui->audioEffectsCombo->currentIndex() > 0) {
+ Phonon::EffectDescription chosenEffect = availableEffects[ui->audioEffectsCombo->currentIndex() - 1];
+
+ QDialog effectDialog;
+ effectDialog.setWindowTitle(tr("Configure effect"));
+ QVBoxLayout *topLayout = new QVBoxLayout(&effectDialog);
+
+ QLabel *description = new QLabel("<b>Description:</b><br>" + chosenEffect.description(), &effectDialog);
+ description->setWordWrap(true);
+ topLayout->addWidget(description);
+
+ QScrollArea *scrollArea = new QScrollArea(&effectDialog);
+ topLayout->addWidget(scrollArea);
+
+ QVariantList savedParamValues;
+ foreach(Phonon::EffectParameter param, nextEffect->parameters()) {
+ savedParamValues << nextEffect->parameterValue(param);
+ }
+
+ QWidget *scrollWidget = new Phonon::EffectWidget(nextEffect);
+ scrollWidget->setMinimumWidth(320);
+ scrollWidget->setContentsMargins(10, 10, 10,10);
+ scrollArea->setWidget(scrollWidget);
+
+ QDialogButtonBox *bbox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &effectDialog);
+ connect(bbox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), &effectDialog, SLOT(accept()));
+ connect(bbox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), &effectDialog, SLOT(reject()));
+ topLayout->addWidget(bbox);
+
+ effectDialog.exec();
+
+ if (effectDialog.result() != QDialog::Accepted) {
+ //we need to restore the paramaters values
+ int currentIndex = 0;
+ foreach(Phonon::EffectParameter param, nextEffect->parameters()) {
+ nextEffect->setParameterValue(param, savedParamValues.at(currentIndex++));
+ }
+
+ }
+ }
+}
+
+void MediaPlayer::handleDrop(QDropEvent *e)
+{
+ QList<QUrl> urls = e->mimeData()->urls();
+ if (e->proposedAction() == Qt::MoveAction){
+ // Just add to the queue:
+ for (int i=0; i<urls.size(); i++)
+ m_MediaObject.enqueue(Phonon::MediaSource(urls[i].toLocalFile()));
+ } else {
+ // Create new queue:
+ m_MediaObject.clearQueue();
+ if (urls.size() > 0) {
+ QString fileName = urls[0].toLocalFile();
+ QDir dir(fileName);
+ if (dir.exists()) {
+ dir.setFilter(QDir::Files);
+ QStringList entries = dir.entryList();
+ if (entries.size() > 0) {
+ setFile(fileName + QDir::separator() + entries[0]);
+ for (int i=1; i< entries.size(); ++i)
+ m_MediaObject.enqueue(fileName + QDir::separator() + entries[i]);
+ }
+ } else {
+ setFile(fileName);
+ for (int i=1; i<urls.size(); i++)
+ m_MediaObject.enqueue(Phonon::MediaSource(urls[i].toLocalFile()));
+ }
+ }
+ }
+ forwardButton->setEnabled(m_MediaObject.queue().size() > 0);
+ m_MediaObject.play();
+}
+
+void MediaPlayer::dropEvent(QDropEvent *e)
+{
+ if (e->mimeData()->hasUrls() && e->proposedAction() != Qt::LinkAction) {
+ e->acceptProposedAction();
+ handleDrop(e);
+ } else {
+ e->ignore();
+ }
+}
+
+void MediaPlayer::dragEnterEvent(QDragEnterEvent *e)
+{
+ dragMoveEvent(e);
+}
+
+void MediaPlayer::dragMoveEvent(QDragMoveEvent *e)
+{
+ if (e->mimeData()->hasUrls()) {
+ if (e->proposedAction() == Qt::CopyAction || e->proposedAction() == Qt::MoveAction){
+ e->acceptProposedAction();
+ }
+ }
+}
+
+void MediaPlayer::playPause()
+{
+ if (m_MediaObject.state() == Phonon::PlayingState)
+ m_MediaObject.pause();
+ else {
+ if (m_MediaObject.currentTime() == m_MediaObject.totalTime())
+ m_MediaObject.seek(0);
+ m_MediaObject.play();
+ }
+}
+
+void MediaPlayer::setFile(const QString &fileName)
+{
+ setWindowTitle(fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1));
+ m_MediaObject.setCurrentSource(Phonon::MediaSource(fileName));
+ m_MediaObject.play();
+}
+
+void MediaPlayer::openFile()
+{
+ QStringList fileNames = QFileDialog::getOpenFileNames(this);
+ m_MediaObject.clearQueue();
+ if (fileNames.size() > 0) {
+ QString fileName = fileNames[0];
+ setFile(fileName);
+ for (int i=1; i<fileNames.size(); i++)
+ m_MediaObject.enqueue(Phonon::MediaSource(fileNames[i]));
+ }
+ forwardButton->setEnabled(m_MediaObject.queue().size() > 0);
+}
+
+void MediaPlayer::bufferStatus(int percent)
+{
+ if (percent == 0 || percent == 100)
+ progressLabel->setText(QString());
+ else {
+ QString str = QString::fromLatin1("(%1%)").arg(percent);
+ progressLabel->setText(str);
+ }
+}
+
+void MediaPlayer::setSaturation(int val)
+{
+ m_videoWidget->setSaturation(val / qreal(SLIDER_RANGE));
+}
+
+void MediaPlayer::setHue(int val)
+{
+ m_videoWidget->setHue(val / qreal(SLIDER_RANGE));
+}
+
+void MediaPlayer::setAspect(int val)
+{
+ m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio(val));
+}
+
+void MediaPlayer::setScale(int val)
+{
+ m_videoWidget->setScaleMode(Phonon::VideoWidget::ScaleMode(val));
+}
+
+void MediaPlayer::setBrightness(int val)
+{
+ m_videoWidget->setBrightness(val / qreal(SLIDER_RANGE));
+}
+
+void MediaPlayer::setContrast(int val)
+{
+ m_videoWidget->setContrast(val / qreal(SLIDER_RANGE));
+}
+
+void MediaPlayer::updateInfo()
+{
+ int maxLength = 30;
+ QString font = "<font color=#ffeeaa>";
+ QString fontmono = "<font family=\"monospace,courier new\" color=#ffeeaa>";
+
+ QMap <QString, QString> metaData = m_MediaObject.metaData();
+ QString trackArtist = metaData.value("ARTIST");
+ if (trackArtist.length() > maxLength)
+ trackArtist = trackArtist.left(maxLength) + "...";
+
+ QString trackTitle = metaData.value("TITLE");
+ int trackBitrate = metaData.value("BITRATE").toInt();
+
+ QString fileName;
+ if (m_MediaObject.currentSource().type() == Phonon::MediaSource::Url) {
+ fileName = m_MediaObject.currentSource().url().toString();
+ } else {
+ fileName = m_MediaObject.currentSource().fileName();
+ fileName = fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1);
+ if (fileName.length() > maxLength)
+ fileName = fileName.left(maxLength) + "...";
+ }
+
+ QString title;
+ if (!trackTitle.isEmpty()) {
+ if (trackTitle.length() > maxLength)
+ trackTitle = trackTitle.left(maxLength) + "...";
+ title = "Title: " + font + trackTitle + "<br></font>";
+ } else if (!fileName.isEmpty()) {
+ if (fileName.length() > maxLength)
+ fileName = fileName.left(maxLength) + "...";
+ title = font + fileName + "</font>";
+ if (m_MediaObject.currentSource().type() == Phonon::MediaSource::Url) {
+ title.prepend("Url: ");
+ } else {
+ title.prepend("File: ");
+ }
+ }
+
+ QString artist;
+ if (!trackArtist.isEmpty())
+ artist = "Artist: " + font + trackArtist + "</font>";
+
+ QString bitrate;
+ if (trackBitrate != 0)
+ bitrate = "<br>Bitrate: " + font + QString::number(trackBitrate/1000) + "kbit</font>";
+
+ info->setText(title + artist + bitrate);
+}
+
+void MediaPlayer::updateTime()
+{
+ long len = m_MediaObject.totalTime();
+ long pos = m_MediaObject.currentTime();
+ QString timeString;
+ if (pos || len)
+ {
+ int sec = pos/1000;
+ int min = sec/60;
+ int hour = min/60;
+ int msec = pos;
+
+ QTime playTime(hour%60, min%60, sec%60, msec%1000);
+ sec = len / 1000;
+ min = sec / 60;
+ hour = min / 60;
+ msec = len;
+
+ QTime stopTime(hour%60, min%60, sec%60, msec%1000);
+ QString timeFormat = "m:ss";
+ if (hour > 0)
+ timeFormat = "h:mm:ss";
+ timeString = playTime.toString(timeFormat);
+ if (len)
+ timeString += " / " + stopTime.toString(timeFormat);
+ }
+ timeLabel->setText(timeString);
+}
+
+void MediaPlayer::rewind()
+{
+ m_MediaObject.seek(0);
+}
+
+void MediaPlayer::forward()
+{
+ QList<Phonon::MediaSource> queue = m_MediaObject.queue();
+ if (queue.size() > 0) {
+ m_MediaObject.setCurrentSource(queue[0]);
+ forwardButton->setEnabled(queue.size() > 1);
+ m_MediaObject.play();
+ }
+}
+
+void MediaPlayer::openUrl()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("BrowserMainWindow"));
+ QString sourceURL = settings.value("location").toString();
+ bool ok = false;
+ sourceURL = QInputDialog::getText(this, tr("Open Location"), tr("Please enter a valid address here:"), QLineEdit::Normal, sourceURL, &ok);
+ if (ok && !sourceURL.isEmpty()) {
+ setWindowTitle(sourceURL.right(sourceURL.length() - sourceURL.lastIndexOf('/') - 1));
+ m_MediaObject.setCurrentSource(Phonon::MediaSource(QUrl::fromEncoded(sourceURL.toUtf8())));
+ m_MediaObject.play();
+ settings.setValue("location", sourceURL);
+ }
+}
+
+void MediaPlayer::finished()
+{
+}
+
+void MediaPlayer::showContextMenu(const QPoint &p)
+{
+ fileMenu->popup(m_videoWidget->isFullScreen() ? p : mapToGlobal(p));
+}
+
+void MediaPlayer::scaleChanged(QAction *act)
+{
+ if (act->text() == tr("Scale and crop"))
+ m_videoWidget->setScaleMode(Phonon::VideoWidget::ScaleAndCrop);
+ else
+ m_videoWidget->setScaleMode(Phonon::VideoWidget::FitInView);
+}
+
+void MediaPlayer::aspectChanged(QAction *act)
+{
+ if (act->text() == tr("16/9"))
+ m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio16_9);
+ else if (act->text() == tr("Scale"))
+ m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatioWidget);
+ else if (act->text() == tr("4/3"))
+ m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio4_3);
+ else
+ m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatioAuto);
+}
+
diff --git a/demos/mediaplayer/mediaplayer.h b/demos/mediaplayer/mediaplayer.h
new file mode 100644
index 0000000..d162435
--- /dev/null
+++ b/demos/mediaplayer/mediaplayer.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+***************************************************************************/
+
+#ifndef MEDIALAYER_H
+#define MEDIAPLAYER_H
+
+#include <QtGui/QWidget>
+#include <QtGui/QApplication>
+#include <QtCore/QTimerEvent>
+#include <QtGui/QShowEvent>
+#include <QtGui/QIcon>
+
+#include <Phonon/AudioOutput>
+#include <Phonon/BackendCapabilities>
+#include <Phonon/Effect>
+#include <Phonon/EffectParameter>
+#include <Phonon/EffectWidget>
+#include <Phonon/MediaObject>
+#include <Phonon/SeekSlider>
+#include <Phonon/VideoWidget>
+#include <Phonon/VolumeSlider>
+
+QT_BEGIN_NAMESPACE
+class QPushButton;
+class QLabel;
+class QSlider;
+class QTextEdit;
+class QMenu;
+class Ui_settings;
+QT_END_NAMESPACE
+
+class MediaPlayer :
+ public QWidget
+{
+ Q_OBJECT
+public:
+ MediaPlayer(const QString &);
+
+ void dragEnterEvent(QDragEnterEvent *e);
+ void dragMoveEvent(QDragMoveEvent *e);
+ void dropEvent(QDropEvent *e);
+ void handleDrop(QDropEvent *e);
+ void setFile(const QString &text);
+ void initVideoWindow();
+ void initSettingsDialog();
+
+public slots:
+ void openFile();
+ void rewind();
+ void forward();
+ void updateInfo();
+ void updateTime();
+ void finished();
+ void playPause();
+ void scaleChanged(QAction *);
+ void aspectChanged(QAction *);
+
+private slots:
+ void setAspect(int);
+ void setScale(int);
+ void setSaturation(int);
+ void setContrast(int);
+ void setHue(int);
+ void setBrightness(int);
+ void stateChanged(Phonon::State newstate, Phonon::State oldstate);
+ void effectChanged();
+ void showSettingsDialog();
+ void showContextMenu(const QPoint &);
+ void bufferStatus(int percent);
+ void openUrl();
+ void configureEffect();
+
+private:
+ QIcon playIcon;
+ QIcon pauseIcon;
+ QMenu *fileMenu;
+ QPushButton *playButton;
+ QPushButton *rewindButton;
+ QPushButton *forwardButton;
+ Phonon::SeekSlider *slider;
+ QLabel *timeLabel;
+ QLabel *progressLabel;
+ Phonon::VolumeSlider *volume;
+ QSlider *m_hueSlider;
+ QSlider *m_satSlider;
+ QSlider *m_contSlider;
+ QLabel *info;
+ Phonon::Effect *nextEffect;
+ QDialog *settingsDialog;
+ Ui_settings *ui;
+
+ QWidget m_videoWindow;
+ Phonon::MediaObject m_MediaObject;
+ Phonon::AudioOutput m_AudioOutput;
+ Phonon::VideoWidget *m_videoWidget;
+ Phonon::Path m_audioOutputPath;
+};
+
+#endif //MEDIAPLAYER_H
diff --git a/demos/mediaplayer/mediaplayer.pro b/demos/mediaplayer/mediaplayer.pro
new file mode 100644
index 0000000..001989d
--- /dev/null
+++ b/demos/mediaplayer/mediaplayer.pro
@@ -0,0 +1,28 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Thu Aug 23 18:02:14 2007
+######################################################################
+
+TEMPLATE = app
+TARGET =
+DEPENDPATH += . build src ui
+
+QT += phonon
+
+FORMS += settings.ui
+RESOURCES += mediaplayer.qrc
+
+!win32:CONFIG += CONSOLE
+
+SOURCES += main.cpp mediaplayer.cpp
+HEADERS += mediaplayer.h
+
+target.path = $$[QT_INSTALL_DEMOS]/mediaplayer
+sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.pro *.html *.doc images
+sources.path = $$[QT_INSTALL_DEMOS]/mediaplayer
+INSTALLS += target sources
+
+wince*{
+DEPLOYMENT_PLUGIN += phonon_ds9 phonon_waveout
+}
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
diff --git a/demos/mediaplayer/mediaplayer.qrc b/demos/mediaplayer/mediaplayer.qrc
new file mode 100644
index 0000000..bcdf404
--- /dev/null
+++ b/demos/mediaplayer/mediaplayer.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>images/screen.png</file>
+</qresource>
+</RCC>
diff --git a/demos/mediaplayer/settings.ui b/demos/mediaplayer/settings.ui
new file mode 100644
index 0000000..d2cedd4
--- /dev/null
+++ b/demos/mediaplayer/settings.ui
@@ -0,0 +1,464 @@
+<ui version="4.0" >
+ <class>settings</class>
+ <widget class="QDialog" name="settings" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>360</width>
+ <height>362</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Settings</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2" >
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="title" >
+ <string>Video options:</string>
+ </property>
+ <property name="flat" >
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_9" >
+ <property name="text" >
+ <string>Contrast:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2" >
+ <widget class="QSlider" name="contrastSlider" >
+ <property name="minimum" >
+ <number>-8</number>
+ </property>
+ <property name="maximum" >
+ <number>8</number>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition" >
+ <enum>QSlider::TicksBelow</enum>
+ </property>
+ <property name="tickInterval" >
+ <number>4</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_8" >
+ <property name="text" >
+ <string>Brightness:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2" >
+ <widget class="QSlider" name="brightnessSlider" >
+ <property name="minimum" >
+ <number>-8</number>
+ </property>
+ <property name="maximum" >
+ <number>8</number>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition" >
+ <enum>QSlider::TicksBelow</enum>
+ </property>
+ <property name="tickInterval" >
+ <number>4</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_7" >
+ <property name="text" >
+ <string>Saturation:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" colspan="2" >
+ <widget class="QSlider" name="saturationSlider" >
+ <property name="minimum" >
+ <number>-8</number>
+ </property>
+ <property name="maximum" >
+ <number>8</number>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition" >
+ <enum>QSlider::TicksBelow</enum>
+ </property>
+ <property name="tickInterval" >
+ <number>4</number>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Hue:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2" >
+ <widget class="QSlider" name="hueSlider" >
+ <property name="minimum" >
+ <number>-8</number>
+ </property>
+ <property name="maximum" >
+ <number>8</number>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition" >
+ <enum>QSlider::TicksBelow</enum>
+ </property>
+ <property name="tickInterval" >
+ <number>4</number>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="2" >
+ <widget class="QLabel" name="label_10" >
+ <property name="text" >
+ <string>Aspect ratio:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="2" >
+ <widget class="QComboBox" name="aspectCombo" >
+ <property name="minimumSize" >
+ <size>
+ <width>180</width>
+ <height>0</height>
+ </size>
+ </property>
+ <item>
+ <property name="text" >
+ <string>Auto</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Stretch</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>4/3</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>16/9</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="5" column="0" colspan="2" >
+ <widget class="QLabel" name="label_11" >
+ <property name="text" >
+ <string>Scale Mode:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="2" >
+ <widget class="QComboBox" name="scalemodeCombo" >
+ <property name="minimumSize" >
+ <size>
+ <width>180</width>
+ <height>0</height>
+ </size>
+ </property>
+ <item>
+ <property name="text" >
+ <string>Fit in view</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Scale and crop</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="title" >
+ <string>Audio options:</string>
+ </property>
+ <property name="flat" >
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Maximum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Audio device:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="deviceCombo" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <widget class="QLabel" name="label_6" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Maximum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Audio effect:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="audioEffectsCombo" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Maximum" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="effectButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Setup</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="crossFadeLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Maximum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>90</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Cross fade:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QSlider" name="crossFadeSlider" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum" >
+ <number>-20</number>
+ </property>
+ <property name="maximum" >
+ <number>20</number>
+ </property>
+ <property name="singleStep" >
+ <number>1</number>
+ </property>
+ <property name="pageStep" >
+ <number>2</number>
+ </property>
+ <property name="value" >
+ <number>0</number>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition" >
+ <enum>QSlider::TicksBelow</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="crossFadeLabel1" >
+ <property name="font" >
+ <font>
+ <pointsize>9</pointsize>
+ </font>
+ </property>
+ <property name="text" >
+ <string>-10 Sec</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="crossFadeLabel2" >
+ <property name="font" >
+ <font>
+ <pointsize>9</pointsize>
+ </font>
+ </property>
+ <property name="text" >
+ <string>0</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="crossFadeLabel3" >
+ <property name="font" >
+ <font>
+ <pointsize>9</pointsize>
+ </font>
+ </property>
+ <property name="text" >
+ <string>10 Sec</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>settings</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>settings</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/demos/pathstroke/main.cpp b/demos/pathstroke/main.cpp
new file mode 100644
index 0000000..613d835
--- /dev/null
+++ b/demos/pathstroke/main.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pathstroke.h"
+#include <QApplication>
+
+int main(int argc, char **argv)
+{
+ Q_INIT_RESOURCE(pathstroke);
+
+ QApplication app(argc, argv);
+
+ bool smallScreen = false;
+ for (int i=0; i<argc; i++)
+ if (QString(argv[i]) == "-small-screen")
+ smallScreen = true;
+
+ PathStrokeWidget pathStrokeWidget(smallScreen);
+ QStyle *arthurStyle = new ArthurStyle();
+ pathStrokeWidget.setStyle(arthurStyle);
+ QList<QWidget *> widgets = qFindChildren<QWidget *>(&pathStrokeWidget);
+ foreach (QWidget *w, widgets)
+ w->setStyle(arthurStyle);
+
+ if (smallScreen)
+ pathStrokeWidget.showFullScreen();
+ else
+ pathStrokeWidget.show();
+
+ return app.exec();
+}
diff --git a/demos/pathstroke/pathstroke.cpp b/demos/pathstroke/pathstroke.cpp
new file mode 100644
index 0000000..d079490
--- /dev/null
+++ b/demos/pathstroke/pathstroke.cpp
@@ -0,0 +1,599 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pathstroke.h"
+#include "arthurstyle.h"
+#include "arthurwidgets.h"
+
+#include <stdio.h>
+
+extern void draw_round_rect(QPainter *p, const QRect &bounds, int radius);
+
+
+PathStrokeControls::PathStrokeControls(QWidget* parent, PathStrokeRenderer* renderer, bool smallScreen)
+ : QWidget(parent)
+{
+ m_renderer = renderer;
+
+ if (smallScreen)
+ layoutForSmallScreens();
+ else
+ layoutForDesktop();
+}
+
+void PathStrokeControls::createCommonControls(QWidget* parent)
+{
+ m_capGroup = new QGroupBox(parent);
+ m_capGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ QRadioButton *flatCap = new QRadioButton(m_capGroup);
+ QRadioButton *squareCap = new QRadioButton(m_capGroup);
+ QRadioButton *roundCap = new QRadioButton(m_capGroup);
+ m_capGroup->setTitle(tr("Cap Style"));
+ flatCap->setText(tr("Flat"));
+ squareCap->setText(tr("Square"));
+ roundCap->setText(tr("Round"));
+ flatCap->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ squareCap->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ roundCap->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+ m_joinGroup = new QGroupBox(parent);
+ m_joinGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ QRadioButton *bevelJoin = new QRadioButton(m_joinGroup);
+ QRadioButton *miterJoin = new QRadioButton(m_joinGroup);
+ QRadioButton *roundJoin = new QRadioButton(m_joinGroup);
+ m_joinGroup->setTitle(tr("Join Style"));
+ bevelJoin->setText(tr("Bevel"));
+ miterJoin->setText(tr("Miter"));
+ roundJoin->setText(tr("Round"));
+
+ m_styleGroup = new QGroupBox(parent);
+ m_styleGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ QRadioButton *solidLine = new QRadioButton(m_styleGroup);
+ QRadioButton *dashLine = new QRadioButton(m_styleGroup);
+ QRadioButton *dotLine = new QRadioButton(m_styleGroup);
+ QRadioButton *dashDotLine = new QRadioButton(m_styleGroup);
+ QRadioButton *dashDotDotLine = new QRadioButton(m_styleGroup);
+ QRadioButton *customDashLine = new QRadioButton(m_styleGroup);
+ m_styleGroup->setTitle(tr("Pen Style"));
+
+ QPixmap line_solid(":res/images/line_solid.png");
+ solidLine->setIcon(line_solid);
+ solidLine->setIconSize(line_solid.size());
+ QPixmap line_dashed(":res/images/line_dashed.png");
+ dashLine->setIcon(line_dashed);
+ dashLine->setIconSize(line_dashed.size());
+ QPixmap line_dotted(":res/images/line_dotted.png");
+ dotLine->setIcon(line_dotted);
+ dotLine->setIconSize(line_dotted.size());
+ QPixmap line_dash_dot(":res/images/line_dash_dot.png");
+ dashDotLine->setIcon(line_dash_dot);
+ dashDotLine->setIconSize(line_dash_dot.size());
+ QPixmap line_dash_dot_dot(":res/images/line_dash_dot_dot.png");
+ dashDotDotLine->setIcon(line_dash_dot_dot);
+ dashDotDotLine->setIconSize(line_dash_dot_dot.size());
+ customDashLine->setText(tr("Custom"));
+
+ int fixedHeight = bevelJoin->sizeHint().height();
+ solidLine->setFixedHeight(fixedHeight);
+ dashLine->setFixedHeight(fixedHeight);
+ dotLine->setFixedHeight(fixedHeight);
+ dashDotLine->setFixedHeight(fixedHeight);
+ dashDotDotLine->setFixedHeight(fixedHeight);
+
+ m_pathModeGroup = new QGroupBox(parent);
+ m_pathModeGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ QRadioButton *curveMode = new QRadioButton(m_pathModeGroup);
+ QRadioButton *lineMode = new QRadioButton(m_pathModeGroup);
+ m_pathModeGroup->setTitle(tr("Line Style"));
+ curveMode->setText(tr("Curves"));
+ lineMode->setText(tr("Lines"));
+
+
+ // Layouts
+ QVBoxLayout *capGroupLayout = new QVBoxLayout(m_capGroup);
+ capGroupLayout->addWidget(flatCap);
+ capGroupLayout->addWidget(squareCap);
+ capGroupLayout->addWidget(roundCap);
+
+ QVBoxLayout *joinGroupLayout = new QVBoxLayout(m_joinGroup);
+ joinGroupLayout->addWidget(bevelJoin);
+ joinGroupLayout->addWidget(miterJoin);
+ joinGroupLayout->addWidget(roundJoin);
+
+ QVBoxLayout *styleGroupLayout = new QVBoxLayout(m_styleGroup);
+ styleGroupLayout->addWidget(solidLine);
+ styleGroupLayout->addWidget(dashLine);
+ styleGroupLayout->addWidget(dotLine);
+ styleGroupLayout->addWidget(dashDotLine);
+ styleGroupLayout->addWidget(dashDotDotLine);
+ styleGroupLayout->addWidget(customDashLine);
+
+ QVBoxLayout *pathModeGroupLayout = new QVBoxLayout(m_pathModeGroup);
+ pathModeGroupLayout->addWidget(curveMode);
+ pathModeGroupLayout->addWidget(lineMode);
+
+
+ // Connections
+ connect(flatCap, SIGNAL(clicked()), m_renderer, SLOT(setFlatCap()));
+ connect(squareCap, SIGNAL(clicked()), m_renderer, SLOT(setSquareCap()));
+ connect(roundCap, SIGNAL(clicked()), m_renderer, SLOT(setRoundCap()));
+
+ connect(bevelJoin, SIGNAL(clicked()), m_renderer, SLOT(setBevelJoin()));
+ connect(miterJoin, SIGNAL(clicked()), m_renderer, SLOT(setMiterJoin()));
+ connect(roundJoin, SIGNAL(clicked()), m_renderer, SLOT(setRoundJoin()));
+
+ connect(curveMode, SIGNAL(clicked()), m_renderer, SLOT(setCurveMode()));
+ connect(lineMode, SIGNAL(clicked()), m_renderer, SLOT(setLineMode()));
+
+ connect(solidLine, SIGNAL(clicked()), m_renderer, SLOT(setSolidLine()));
+ connect(dashLine, SIGNAL(clicked()), m_renderer, SLOT(setDashLine()));
+ connect(dotLine, SIGNAL(clicked()), m_renderer, SLOT(setDotLine()));
+ connect(dashDotLine, SIGNAL(clicked()), m_renderer, SLOT(setDashDotLine()));
+ connect(dashDotDotLine, SIGNAL(clicked()), m_renderer, SLOT(setDashDotDotLine()));
+ connect(customDashLine, SIGNAL(clicked()), m_renderer, SLOT(setCustomDashLine()));
+
+ // Set the defaults:
+ flatCap->setChecked(true);
+ bevelJoin->setChecked(true);
+ curveMode->setChecked(true);
+ solidLine->setChecked(true);
+}
+
+
+void PathStrokeControls::layoutForDesktop()
+{
+ QGroupBox *mainGroup = new QGroupBox(this);
+ mainGroup->setFixedWidth(180);
+ mainGroup->setTitle(tr("Path Stroking"));
+
+ createCommonControls(mainGroup);
+
+ QGroupBox* penWidthGroup = new QGroupBox(mainGroup);
+ QSlider *penWidth = new QSlider(Qt::Horizontal, penWidthGroup);
+ penWidth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ penWidthGroup->setTitle(tr("Pen Width"));
+ penWidth->setRange(0, 500);
+
+ QPushButton *animated = new QPushButton(mainGroup);
+ animated->setText(tr("Animate"));
+ animated->setCheckable(true);
+
+ QPushButton *showSourceButton = new QPushButton(mainGroup);
+ showSourceButton->setText(tr("Show Source"));
+#ifdef QT_OPENGL_SUPPORT
+ QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
+ enableOpenGLButton->setText(tr("Use OpenGL"));
+ enableOpenGLButton->setCheckable(true);
+ enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
+ if (!QGLFormat::hasOpenGL())
+ enableOpenGLButton->hide();
+#endif
+ QPushButton *whatsThisButton = new QPushButton(mainGroup);
+ whatsThisButton->setText(tr("What's This?"));
+ whatsThisButton->setCheckable(true);
+
+
+ // Layouts:
+ QVBoxLayout *penWidthLayout = new QVBoxLayout(penWidthGroup);
+ penWidthLayout->addWidget(penWidth);
+
+ QVBoxLayout * mainLayout = new QVBoxLayout(this);
+ mainLayout->setMargin(0);
+ mainLayout->addWidget(mainGroup);
+
+ QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
+ mainGroupLayout->setMargin(3);
+ mainGroupLayout->addWidget(m_capGroup);
+ mainGroupLayout->addWidget(m_joinGroup);
+ mainGroupLayout->addWidget(m_styleGroup);
+ mainGroupLayout->addWidget(penWidthGroup);
+ mainGroupLayout->addWidget(m_pathModeGroup);
+ mainGroupLayout->addWidget(animated);
+ mainGroupLayout->addStretch(1);
+ mainGroupLayout->addWidget(showSourceButton);
+#ifdef QT_OPENGL_SUPPORT
+ mainGroupLayout->addWidget(enableOpenGLButton);
+#endif
+ mainGroupLayout->addWidget(whatsThisButton);
+
+
+ // Set up connections
+ connect(animated, SIGNAL(toggled(bool)),
+ m_renderer, SLOT(setAnimation(bool)));
+
+ connect(penWidth, SIGNAL(valueChanged(int)),
+ m_renderer, SLOT(setPenWidth(int)));
+
+ connect(showSourceButton, SIGNAL(clicked()), m_renderer, SLOT(showSource()));
+#ifdef QT_OPENGL_SUPPORT
+ connect(enableOpenGLButton, SIGNAL(clicked(bool)), m_renderer, SLOT(enableOpenGL(bool)));
+#endif
+ connect(whatsThisButton, SIGNAL(clicked(bool)), m_renderer, SLOT(setDescriptionEnabled(bool)));
+ connect(m_renderer, SIGNAL(descriptionEnabledChanged(bool)),
+ whatsThisButton, SLOT(setChecked(bool)));
+
+
+ // Set the defaults
+ animated->setChecked(true);
+ penWidth->setValue(50);
+
+}
+
+void PathStrokeControls::layoutForSmallScreens()
+{
+ createCommonControls(this);
+
+ m_capGroup->layout()->setMargin(0);
+ m_joinGroup->layout()->setMargin(0);
+ m_styleGroup->layout()->setMargin(0);
+ m_pathModeGroup->layout()->setMargin(0);
+
+ QPushButton* okBtn = new QPushButton(tr("OK"), this);
+ okBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ okBtn->setMinimumSize(100,okBtn->minimumSize().height());
+
+ QPushButton* quitBtn = new QPushButton(tr("Quit"), this);
+ quitBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ quitBtn->setMinimumSize(100, okBtn->minimumSize().height());
+
+ QLabel *penWidthLabel = new QLabel(tr(" Width:"));
+ QSlider *penWidth = new QSlider(Qt::Horizontal, this);
+ penWidth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ penWidth->setRange(0, 500);
+
+#ifdef QT_OPENGL_SUPPORT
+ QPushButton *enableOpenGLButton = new QPushButton(this);
+ enableOpenGLButton->setText(tr("Use OpenGL"));
+ enableOpenGLButton->setCheckable(true);
+ enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
+ if (!QGLFormat::hasOpenGL())
+ enableOpenGLButton->hide();
+#endif
+
+ // Layouts:
+ QHBoxLayout *penWidthLayout = new QHBoxLayout(0);
+ penWidthLayout->addWidget(penWidthLabel, 0, Qt::AlignRight);
+ penWidthLayout->addWidget(penWidth);
+
+ QVBoxLayout *leftLayout = new QVBoxLayout(0);
+ leftLayout->addWidget(m_capGroup);
+ leftLayout->addWidget(m_joinGroup);
+#ifdef QT_OPENGL_SUPPORT
+ leftLayout->addWidget(enableOpenGLButton);
+#endif
+ leftLayout->addLayout(penWidthLayout);
+
+ QVBoxLayout *rightLayout = new QVBoxLayout(0);
+ rightLayout->addWidget(m_styleGroup);
+ rightLayout->addWidget(m_pathModeGroup);
+
+ QGridLayout *mainLayout = new QGridLayout(this);
+ mainLayout->setMargin(0);
+
+ // Add spacers around the form items so we don't look stupid at higher resolutions
+ mainLayout->addItem(new QSpacerItem(0,0), 0, 0, 1, 4);
+ mainLayout->addItem(new QSpacerItem(0,0), 1, 0, 2, 1);
+ mainLayout->addItem(new QSpacerItem(0,0), 1, 3, 2, 1);
+ mainLayout->addItem(new QSpacerItem(0,0), 3, 0, 1, 4);
+
+ mainLayout->addLayout(leftLayout, 1, 1);
+ mainLayout->addLayout(rightLayout, 1, 2);
+ mainLayout->addWidget(quitBtn, 2, 1, Qt::AlignHCenter | Qt::AlignTop);
+ mainLayout->addWidget(okBtn, 2, 2, Qt::AlignHCenter | Qt::AlignTop);
+
+#ifdef QT_OPENGL_SUPPORT
+ connect(enableOpenGLButton, SIGNAL(clicked(bool)), m_renderer, SLOT(enableOpenGL(bool)));
+#endif
+
+ connect(penWidth, SIGNAL(valueChanged(int)), m_renderer, SLOT(setPenWidth(int)));
+ connect(quitBtn, SIGNAL(clicked()), this, SLOT(emitQuitSignal()));
+ connect(okBtn, SIGNAL(clicked()), this, SLOT(emitOkSignal()));
+
+ m_renderer->setAnimation(true);
+ penWidth->setValue(50);
+}
+
+void PathStrokeControls::emitQuitSignal()
+{ emit quitPressed(); }
+
+void PathStrokeControls::emitOkSignal()
+{ emit okPressed(); }
+
+
+PathStrokeWidget::PathStrokeWidget(bool smallScreen)
+{
+ setWindowTitle(tr("Path Stroking"));
+
+ // Widget construction and property setting
+ m_renderer = new PathStrokeRenderer(this, smallScreen);
+
+ m_controls = new PathStrokeControls(0, m_renderer, smallScreen);
+
+ // Layouting
+ QHBoxLayout *viewLayout = new QHBoxLayout(this);
+ viewLayout->addWidget(m_renderer);
+
+ if (!smallScreen)
+ viewLayout->addWidget(m_controls);
+
+ m_renderer->loadSourceFile(":res/pathstroke/pathstroke.cpp");
+ m_renderer->loadDescription(":res/pathstroke/pathstroke.html");
+
+ connect(m_renderer, SIGNAL(clicked()), this, SLOT(showControls()));
+ connect(m_controls, SIGNAL(okPressed()), this, SLOT(hideControls()));
+ connect(m_controls, SIGNAL(quitPressed()), QApplication::instance(), SLOT(quit()));
+}
+
+
+void PathStrokeWidget::showControls()
+{
+ m_controls->showFullScreen();
+}
+
+
+void PathStrokeWidget::hideControls()
+{
+ m_controls->hide();
+}
+
+
+void PathStrokeWidget::setStyle( QStyle * style )
+{
+ QWidget::setStyle(style);
+ if (m_controls != 0)
+ {
+ m_controls->setStyle(style);
+
+ QList<QWidget *> widgets = qFindChildren<QWidget *>(m_controls);
+ foreach (QWidget *w, widgets)
+ w->setStyle(style);
+ }
+}
+
+
+PathStrokeRenderer::PathStrokeRenderer(QWidget *parent, bool smallScreen)
+ : ArthurFrame(parent)
+{
+ m_smallScreen = smallScreen;
+ m_pointSize = 10;
+ m_activePoint = -1;
+ m_capStyle = Qt::FlatCap;
+ m_joinStyle = Qt::BevelJoin;
+ m_pathMode = CurveMode;
+ m_penWidth = 1;
+ m_penStyle = Qt::SolidLine;
+ m_wasAnimated = true;
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+}
+
+void PathStrokeRenderer::paint(QPainter *painter)
+{
+ if (m_points.isEmpty())
+ initializePoints();
+
+ painter->setRenderHint(QPainter::Antialiasing);
+
+ QPalette pal = palette();
+ painter->setPen(Qt::NoPen);
+
+ // Construct the path
+ QPainterPath path;
+ path.moveTo(m_points.at(0));
+
+ if (m_pathMode == LineMode) {
+ for (int i=1; i<m_points.size(); ++i) {
+ path.lineTo(m_points.at(i));
+ }
+ } else {
+ int i=1;
+ while (i + 2 < m_points.size()) {
+ path.cubicTo(m_points.at(i), m_points.at(i+1), m_points.at(i+2));
+ i += 3;
+ }
+ while (i < m_points.size()) {
+ path.lineTo(m_points.at(i));
+ ++i;
+ }
+ }
+
+ // Draw the path
+ {
+ QColor lg = Qt::red;
+
+ // The "custom" pen
+ if (m_penStyle == Qt::NoPen) {
+ QPainterPathStroker stroker;
+ stroker.setWidth(m_penWidth);
+ stroker.setJoinStyle(m_joinStyle);
+ stroker.setCapStyle(m_capStyle);
+
+ QVector<qreal> dashes;
+ qreal space = 4;
+ dashes << 1 << space
+ << 3 << space
+ << 9 << space
+ << 27 << space
+ << 9 << space
+ << 3 << space;
+ stroker.setDashPattern(dashes);
+ QPainterPath stroke = stroker.createStroke(path);
+ painter->fillPath(stroke, lg);
+
+ } else {
+ QPen pen(lg, m_penWidth, m_penStyle, m_capStyle, m_joinStyle);
+ painter->strokePath(path, pen);
+ }
+ }
+
+ if (1) {
+ // Draw the control points
+ painter->setPen(QColor(50, 100, 120, 200));
+ painter->setBrush(QColor(200, 200, 210, 120));
+ for (int i=0; i<m_points.size(); ++i) {
+ QPointF pos = m_points.at(i);
+ painter->drawEllipse(QRectF(pos.x() - m_pointSize,
+ pos.y() - m_pointSize,
+ m_pointSize*2, m_pointSize*2));
+ }
+ painter->setPen(QPen(Qt::lightGray, 0, Qt::SolidLine));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawPolyline(m_points);
+ }
+
+}
+
+void PathStrokeRenderer::initializePoints()
+{
+ const int count = 7;
+ m_points.clear();
+ m_vectors.clear();
+
+ QMatrix m;
+ qreal rot = 360 / count;
+ QPointF center(width() / 2, height() / 2);
+ QMatrix vm;
+ vm.shear(2, -1);
+ vm.scale(3, 3);
+
+ for (int i=0; i<count; ++i) {
+ m_vectors << QPointF(.1f, .25f) * (m * vm);
+ m_points << QPointF(0, 100) * m + center;
+ m.rotate(rot);
+ }
+}
+
+void PathStrokeRenderer::updatePoints()
+{
+ qreal pad = 10;
+ qreal left = pad;
+ qreal right = width() - pad;
+ qreal top = pad;
+ qreal bottom = height() - pad;
+
+ Q_ASSERT(m_points.size() == m_vectors.size());
+ for (int i=0; i<m_points.size(); ++i) {
+
+ if (i == m_activePoint)
+ continue;
+
+ QPointF pos = m_points.at(i);
+ QPointF vec = m_vectors.at(i);
+ pos += vec;
+ if (pos.x() < left || pos.x() > right) {
+ vec.setX(-vec.x());
+ pos.setX(pos.x() < left ? left : right);
+ } if (pos.y() < top || pos.y() > bottom) {
+ vec.setY(-vec.y());
+ pos.setY(pos.y() < top ? top : bottom);
+ }
+ m_points[i] = pos;
+ m_vectors[i] = vec;
+ }
+ update();
+}
+
+void PathStrokeRenderer::mousePressEvent(QMouseEvent *e)
+{
+ setDescriptionEnabled(false);
+ m_activePoint = -1;
+ qreal distance = -1;
+ for (int i=0; i<m_points.size(); ++i) {
+ qreal d = QLineF(e->pos(), m_points.at(i)).length();
+ if ((distance < 0 && d < 8 * m_pointSize) || d < distance) {
+ distance = d;
+ m_activePoint = i;
+ }
+ }
+
+ if (m_activePoint != -1) {
+ m_wasAnimated = m_timer.isActive();
+ setAnimation(false);
+ mouseMoveEvent(e);
+ }
+
+ // If we're not running in small screen mode, always assume we're dragging
+ m_mouseDrag = !m_smallScreen;
+ m_mousePress = e->pos();
+}
+
+void PathStrokeRenderer::mouseMoveEvent(QMouseEvent *e)
+{
+ // If we've moved more then 25 pixels, assume user is dragging
+ if (!m_mouseDrag && QPoint(m_mousePress - e->pos()).manhattanLength() > 25)
+ m_mouseDrag = true;
+
+ if (m_mouseDrag && m_activePoint >= 0 && m_activePoint < m_points.size()) {
+ m_points[m_activePoint] = e->pos();
+ update();
+ }
+}
+
+void PathStrokeRenderer::mouseReleaseEvent(QMouseEvent *)
+{
+ m_activePoint = -1;
+ setAnimation(m_wasAnimated);
+
+ if (!m_mouseDrag && m_smallScreen)
+ emit clicked();
+}
+
+void PathStrokeRenderer::timerEvent(QTimerEvent *e)
+{
+ if (e->timerId() == m_timer.timerId()) {
+ updatePoints();
+ QApplication::syncX();
+ } // else if (e->timerId() == m_fpsTimer.timerId()) {
+// emit frameRate(m_frameCount);
+// m_frameCount = 0;
+// }
+}
+
+void PathStrokeRenderer::setAnimation(bool animation)
+{
+ m_timer.stop();
+// m_fpsTimer.stop();
+
+ if (animation) {
+ m_timer.start(25, this);
+// m_fpsTimer.start(1000, this);
+// m_frameCount = 0;
+ }
+}
diff --git a/demos/pathstroke/pathstroke.h b/demos/pathstroke/pathstroke.h
new file mode 100644
index 0000000..99f17a7
--- /dev/null
+++ b/demos/pathstroke/pathstroke.h
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PATHSTROKE_H
+#define PATHSTROKE_H
+
+#include "arthurwidgets.h"
+#include <QtGui>
+
+class PathStrokeRenderer : public ArthurFrame
+{
+ Q_OBJECT
+ Q_PROPERTY(bool animation READ animation WRITE setAnimation)
+ Q_PROPERTY(qreal penWidth READ realPenWidth WRITE setRealPenWidth)
+public:
+ enum PathMode { CurveMode, LineMode };
+
+ PathStrokeRenderer(QWidget *parent, bool smallScreen = false);
+
+ void paint(QPainter *);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void timerEvent(QTimerEvent *e);
+
+ QSize sizeHint() const { return QSize(500, 500); }
+
+ bool animation() const { return m_timer.isActive(); }
+
+ qreal realPenWidth() const { return m_penWidth; }
+ void setRealPenWidth(qreal penWidth) { m_penWidth = penWidth; update(); }
+
+signals:
+ void clicked();
+
+public slots:
+ void setPenWidth(int penWidth) { m_penWidth = penWidth / 10.0; update(); }
+ void setAnimation(bool animation);
+
+ void setFlatCap() { m_capStyle = Qt::FlatCap; update(); }
+ void setSquareCap() { m_capStyle = Qt::SquareCap; update(); }
+ void setRoundCap() { m_capStyle = Qt::RoundCap; update(); }
+
+ void setBevelJoin() { m_joinStyle = Qt::BevelJoin; update(); }
+ void setMiterJoin() { m_joinStyle = Qt::MiterJoin; update(); }
+ void setRoundJoin() { m_joinStyle = Qt::RoundJoin; update(); }
+
+ void setCurveMode() { m_pathMode = CurveMode; update(); }
+ void setLineMode() { m_pathMode = LineMode; update(); }
+
+ void setSolidLine() { m_penStyle = Qt::SolidLine; update(); }
+ void setDashLine() { m_penStyle = Qt::DashLine; update(); }
+ void setDotLine() { m_penStyle = Qt::DotLine; update(); }
+ void setDashDotLine() { m_penStyle = Qt::DashDotLine; update(); }
+ void setDashDotDotLine() { m_penStyle = Qt::DashDotDotLine; update(); }
+ void setCustomDashLine() { m_penStyle = Qt::NoPen; update(); }
+
+private:
+ void initializePoints();
+ void updatePoints();
+
+ QBasicTimer m_timer;
+
+ PathMode m_pathMode;
+
+ bool m_wasAnimated;
+
+ qreal m_penWidth;
+ int m_pointCount;
+ int m_pointSize;
+ int m_activePoint;
+ QVector<QPointF> m_points;
+ QVector<QPointF> m_vectors;
+
+ Qt::PenJoinStyle m_joinStyle;
+ Qt::PenCapStyle m_capStyle;
+
+ Qt::PenStyle m_penStyle;
+
+ bool m_smallScreen;
+ QPoint m_mousePress;
+ bool m_mouseDrag;
+};
+
+class PathStrokeControls : public QWidget
+{
+ Q_OBJECT
+public:
+ PathStrokeControls(QWidget* parent, PathStrokeRenderer* renderer, bool smallScreen);
+
+signals:
+ void okPressed();
+ void quitPressed();
+
+private:
+ PathStrokeRenderer* m_renderer;
+
+ QGroupBox *m_capGroup;
+ QGroupBox *m_joinGroup;
+ QGroupBox *m_styleGroup;
+ QGroupBox *m_pathModeGroup;
+
+ void createCommonControls(QWidget* parent);
+ void layoutForDesktop();
+ void layoutForSmallScreens();
+
+private slots:
+ void emitQuitSignal();
+ void emitOkSignal();
+
+};
+
+class PathStrokeWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ PathStrokeWidget(bool smallScreen);
+ void setStyle ( QStyle * style );
+
+private:
+ PathStrokeRenderer *m_renderer;
+ PathStrokeControls *m_controls;
+
+private slots:
+ void showControls();
+ void hideControls();
+
+};
+
+#endif // PATHSTROKE_H
diff --git a/demos/pathstroke/pathstroke.html b/demos/pathstroke/pathstroke.html
new file mode 100644
index 0000000..9e7e50d
--- /dev/null
+++ b/demos/pathstroke/pathstroke.html
@@ -0,0 +1,20 @@
+<html>
+<center>
+<h2>Primitive Stroking</h2>
+</center>
+
+<p>In this demo we show some of the various types of pens that can be
+used in Qt.</p>
+
+<p>Qt defines cap styles for how the end points are treated and join
+styles for how path segments are joined together. A standard set of
+predefined dash patterns are also included that can be used with
+<code>QPen</code>.</p>
+
+<p>In addition to the predefined patterns available in
+<code>QPen</code> we also demonstrate direct use of the
+<code>QPainterPathStroker</code> class which can be used to define
+custom dash patterns. You can see this by enabling the
+<i>Custom Pattern</i> option.</p>
+
+</html>
diff --git a/demos/pathstroke/pathstroke.pro b/demos/pathstroke/pathstroke.pro
new file mode 100644
index 0000000..ce6ab3d
--- /dev/null
+++ b/demos/pathstroke/pathstroke.pro
@@ -0,0 +1,23 @@
+SOURCES += main.cpp pathstroke.cpp
+HEADERS += pathstroke.h
+
+SHARED_FOLDER = ../shared
+
+include($$SHARED_FOLDER/shared.pri)
+
+RESOURCES += pathstroke.qrc
+
+contains(QT_CONFIG, opengl) {
+ DEFINES += QT_OPENGL_SUPPORT
+ QT += opengl
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/pathstroke
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.html
+sources.path = $$[QT_INSTALL_DEMOS]/pathstroke
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
+symbian:TARGET.UID3 = 0xA000A63E \ No newline at end of file
diff --git a/demos/pathstroke/pathstroke.qrc b/demos/pathstroke/pathstroke.qrc
new file mode 100644
index 0000000..a9a7234
--- /dev/null
+++ b/demos/pathstroke/pathstroke.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/res/pathstroke">
+ <file>pathstroke.cpp</file>
+ <file>pathstroke.html</file>
+</qresource>
+</RCC>
diff --git a/demos/qtdemo/Info_mac.plist b/demos/qtdemo/Info_mac.plist
new file mode 100644
index 0000000..71b0059
--- /dev/null
+++ b/demos/qtdemo/Info_mac.plist
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleIconFile</key>
+ <string>@ICON@</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleGetInfoString</key>
+ <string>Created by Qt/QMake</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.trolltech.qt.demo</string>
+ <key>CFBundleExecutable</key>
+ <string>@EXECUTABLE@</string>
+</dict>
+</plist>
diff --git a/demos/qtdemo/colors.cpp b/demos/qtdemo/colors.cpp
new file mode 100644
index 0000000..18343cb
--- /dev/null
+++ b/demos/qtdemo/colors.cpp
@@ -0,0 +1,390 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "colors.h"
+
+#ifndef QT_NO_OPENGL
+ #include <QGLWidget>
+#endif
+//#define QT_NO_OPENGL
+
+// Colors:
+QColor Colors::sceneBg1(QColor(91, 91, 91));
+QColor Colors::sceneBg1Line(QColor(114, 108, 104));
+QColor Colors::sceneBg2(QColor(0, 0, 0));
+QColor Colors::sceneLine(255, 255, 255);
+QColor Colors::paperBg(QColor(100, 100, 100));
+QColor Colors::menuTextFg(QColor(255, 0, 0));
+QColor Colors::buttonBgLow(QColor(255, 255, 255, 90));
+QColor Colors::buttonBgHigh(QColor(255, 255, 255, 20));
+QColor Colors::buttonText(QColor(255, 255, 255));
+QColor Colors::tt_green(QColor(166, 206, 57));
+QColor Colors::fadeOut(QColor(206, 246, 117, 0));
+QColor Colors::heading(QColor(190,230,80));
+QString Colors::contentColor("<font color='#eeeeee'>");
+QString Colors::glVersion("Not detected!");
+
+// Guides:
+int Colors::stageStartY = 8;
+int Colors::stageHeight = 536;
+int Colors::stageStartX = 8;
+int Colors::stageWidth = 785;
+int Colors::contentStartY = 22;
+int Colors::contentHeight = 510;
+
+// Properties:
+bool Colors::openGlRendering = false;
+bool Colors::direct3dRendering = false;
+bool Colors::softwareRendering = false;
+bool Colors::openGlAwailable = true;
+bool Colors::direct3dAwailable = true;
+bool Colors::xRenderPresent = true;
+
+bool Colors::noTicker = false;
+bool Colors::noRescale = false;
+bool Colors::noAnimations = false;
+bool Colors::noBlending = false;
+bool Colors::noScreenSync = false;
+bool Colors::fullscreen = false;
+bool Colors::usePixmaps = false;
+bool Colors::useLoop = false;
+bool Colors::showBoundingRect = false;
+bool Colors::showFps = false;
+bool Colors::noAdapt = false;
+bool Colors::noWindowMask = true;
+bool Colors::useButtonBalls = false;
+bool Colors::useEightBitPalette = false;
+bool Colors::noTimerUpdate = false;
+bool Colors::noTickerMorph = false;
+bool Colors::adapted = false;
+bool Colors::verbose = false;
+bool Colors::pause = true;
+int Colors::fps = 100;
+int Colors::menuCount = 18;
+float Colors::animSpeed = 1.0;
+float Colors::animSpeedButtons = 1.0;
+float Colors::benchmarkFps = -1;
+int Colors::tickerLetterCount = 80;
+float Colors::tickerMoveSpeed = 0.4f;
+float Colors::tickerMorphSpeed = 2.5f;
+QString Colors::tickerText = ".EROM ETAERC .SSEL EDOC";
+QString Colors::rootMenuName = "Qt Examples and Demos";
+
+QFont Colors::contentFont()
+{
+ QFont font;
+ font.setStyleStrategy(QFont::PreferAntialias);
+#if defined(Q_OS_MAC)
+ font.setPixelSize(14);
+ font.setFamily("Arial");
+#else
+ font.setPixelSize(13);
+ font.setFamily("Verdana");
+#endif
+ return font;
+}
+
+QFont Colors::headingFont()
+{
+ QFont font;
+ font.setStyleStrategy(QFont::PreferAntialias);
+ font.setPixelSize(23);
+ font.setBold(true);
+ font.setFamily("Verdana");
+ return font;
+}
+
+QFont Colors::buttonFont()
+{
+ QFont font;
+ font.setStyleStrategy(QFont::PreferAntialias);
+#if 0//defined(Q_OS_MAC)
+ font.setPixelSize(11);
+ font.setFamily("Silom");
+#else
+ font.setPixelSize(11);
+ font.setFamily("Verdana");
+#endif
+ return font;
+}
+
+QFont Colors::tickerFont()
+{
+ QFont font;
+ font.setStyleStrategy(QFont::PreferAntialias);
+#if defined(Q_OS_MAC)
+ font.setPixelSize(11);
+ font.setBold(true);
+ font.setFamily("Arial");
+#else
+ font.setPixelSize(10);
+ font.setBold(true);
+ font.setFamily("sans serif");
+#endif
+ return font;
+}
+
+float parseFloat(const QString &argument, const QString &name)
+{
+ if (name.length() == argument.length()){
+ QMessageBox::warning(0, "Arguments",
+ QString("No argument number found for ")
+ + name
+ + ". Remember to put name and value adjacent! (e.g. -fps100)");
+ exit(0);
+ }
+ float value = argument.mid(name.length()).toFloat();
+ return value;
+}
+
+QString parseText(const QString &argument, const QString &name)
+{
+ if (name.length() == argument.length()){
+ QMessageBox::warning(0, "Arguments",
+ QString("No argument number found for ")
+ + name
+ + ". Remember to put name and value adjacent! (e.g. -fps100)");
+ exit(0);
+ }
+ QString value = argument.mid(name.length());
+ return value;
+}
+
+void Colors::parseArgs(int argc, char *argv[])
+{
+ // some arguments should be processed before
+ // others. Handle them now:
+ for (int i=1; i<argc; i++){
+ QString s(argv[i]);
+ if (s == "-verbose")
+ Colors::verbose = true;
+ }
+
+ Colors::detectSystemResources();
+
+ // Handle the rest of the arguments. They may
+ // override attributes already set:
+ for (int i=1; i<argc; i++){
+ QString s(argv[i]);
+ if (s == "-opengl")
+ Colors::openGlRendering = true;
+ else if (s == "-direct3d")
+ Colors::direct3dRendering = true;
+ else if (s == "-software")
+ Colors::softwareRendering = true;
+ else if (s == "-no-opengl") // support old style
+ Colors::softwareRendering = true;
+ else if (s == "-no-ticker") // support old style
+ Colors::noTicker = true;
+ else if (s.startsWith("-ticker"))
+ Colors::noTicker = !bool(parseFloat(s, "-ticker"));
+ else if (s == "-no-animations")
+ Colors::noAnimations = true; // support old style
+ else if (s.startsWith("-animations"))
+ Colors::noAnimations = !bool(parseFloat(s, "-animations"));
+ else if (s == "-no-adapt")
+ Colors::noAdapt = true;
+ else if (s == "-low")
+ Colors::setLowSettings();
+ else if (s == "-no-rescale")
+ Colors::noRescale = true;
+ else if (s == "-use-pixmaps")
+ Colors::usePixmaps = true;
+ else if (s == "-fullscreen")
+ Colors::fullscreen = true;
+ else if (s == "-show-br")
+ Colors::showBoundingRect = true;
+ else if (s == "-show-fps")
+ Colors::showFps = true;
+ else if (s == "-no-blending")
+ Colors::noBlending = true;
+ else if (s == "-no-sync")
+ Colors::noScreenSync = true;
+ else if (s.startsWith("-menu"))
+ Colors::menuCount = int(parseFloat(s, "-menu"));
+ else if (s.startsWith("-use-timer-update"))
+ Colors::noTimerUpdate = !bool(parseFloat(s, "-use-timer-update"));
+ else if (s.startsWith("-pause"))
+ Colors::pause = bool(parseFloat(s, "-pause"));
+ else if (s == "-no-ticker-morph")
+ Colors::noTickerMorph = true;
+ else if (s == "-use-window-mask")
+ Colors::noWindowMask = false;
+ else if (s == "-use-loop")
+ Colors::useLoop = true;
+ else if (s == "-use-8bit")
+ Colors::useEightBitPalette = true;
+ else if (s.startsWith("-8bit"))
+ Colors::useEightBitPalette = bool(parseFloat(s, "-8bit"));
+ else if (s == "-use-balls")
+ Colors::useButtonBalls = true;
+ else if (s.startsWith("-ticker-letters"))
+ Colors::tickerLetterCount = int(parseFloat(s, "-ticker-letters"));
+ else if (s.startsWith("-ticker-text"))
+ Colors::tickerText = parseText(s, "-ticker-text");
+ else if (s.startsWith("-ticker-speed"))
+ Colors::tickerMoveSpeed = parseFloat(s, "-ticker-speed");
+ else if (s.startsWith("-ticker-morph-speed"))
+ Colors::tickerMorphSpeed = parseFloat(s, "-ticker-morph-speed");
+ else if (s.startsWith("-animation-speed"))
+ Colors::animSpeed = parseFloat(s, "-animation-speed");
+ else if (s.startsWith("-fps"))
+ Colors::fps = int(parseFloat(s, "-fps"));
+ else if (s.startsWith("-h") || s.startsWith("-help")){
+ QMessageBox::warning(0, "Arguments",
+ QString("Usage: qtdemo [-verbose] [-no-adapt] [-opengl] [-direct3d] [-software] [-fullscreen] [-ticker[0|1]] ")
+ + "[-animations[0|1]] [-no-blending] [-no-sync] [-use-timer-update[0|1]] [-pause[0|1]] "
+ + "[-use-window-mask] [-no-rescale] "
+ + "[-use-pixmaps] [-show-fps] [-show-br] [-8bit[0|1]] [-menu<int>] [-use-loop] [-use-balls] "
+ + "[-animation-speed<float>] [-fps<int>] "
+ + "[-low] [-ticker-letters<int>] [-ticker-speed<float>] [-no-ticker-morph] "
+ + "[-ticker-morph-speed<float>] [-ticker-text<string>]");
+ exit(0);
+ }
+ }
+
+ Colors::postConfigure();
+}
+
+void Colors::setLowSettings()
+{
+ Colors::openGlRendering = false;
+ Colors::direct3dRendering = false;
+ Colors::softwareRendering = true;
+ Colors::noTicker = true;
+ Colors::noTimerUpdate = true;
+ Colors::fps = 30;
+ Colors::usePixmaps = true;
+ Colors::noAnimations = true;
+ Colors::noBlending = true;
+}
+
+void Colors::detectSystemResources()
+{
+#ifndef QT_NO_OPENGL
+ if (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0)
+ Colors::glVersion = "2.0 or higher";
+ else if (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_5)
+ Colors::glVersion = "1.5";
+ else if (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_4)
+ Colors::glVersion = "1.4";
+ else if (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_3)
+ Colors::glVersion = "1.3 or lower";
+ if (Colors::verbose)
+ qDebug() << "- OpenGL version:" << Colors::glVersion;
+
+ QGLWidget glw;
+ if (!QGLFormat::hasOpenGL()
+ || !glw.format().directRendering()
+ || !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_5)
+ || glw.depth() < 24
+ )
+#else
+ if (Colors::verbose)
+ qDebug() << "- OpenGL not supported by current build of Qt";
+#endif
+ {
+ Colors::openGlAwailable = false;
+ if (Colors::verbose)
+ qDebug("- OpenGL not recommended on this system");
+ }
+
+#if defined(Q_WS_WIN)
+ Colors::direct3dAwailable = false; // for now.
+#endif
+
+#if defined(Q_WS_X11)
+ // check if X render is present:
+ QPixmap tmp(1, 1);
+ if (!tmp.x11PictureHandle()){
+ Colors::xRenderPresent = false;
+ if (Colors::verbose)
+ qDebug("- X render not present");
+ }
+
+#endif
+
+ QWidget w;
+ if (Colors::verbose)
+ qDebug() << "- Color depth: " << QString::number(w.depth());
+}
+
+void Colors::postConfigure()
+{
+ if (!Colors::noAdapt){
+ QWidget w;
+ if (w.depth() < 16){
+ Colors::useEightBitPalette = true;
+ Colors::adapted = true;
+ if (Colors::verbose)
+ qDebug() << "- Adapt: Color depth less than 16 bit. Using 8 bit palette";
+ }
+
+ if (!Colors::xRenderPresent){
+ Colors::setLowSettings();
+ Colors::adapted = true;
+ if (Colors::verbose)
+ qDebug() << "- Adapt: X renderer not present. Using low settings";
+ }
+ }
+
+#if !defined(Q_WS_WIN)
+ if (Colors::direct3dRendering){
+ Colors::direct3dRendering = false;
+ qDebug() << "- WARNING: Direct3D specified, but not supported on this platform";
+ }
+#endif
+
+ if (!Colors::openGlRendering && !Colors::direct3dRendering && !Colors::softwareRendering){
+ // The user has not decided rendering system. So we do it instead:
+#if defined(Q_WS_WIN)
+ if (Colors::direct3dAwailable)
+ Colors::direct3dRendering = true;
+ else
+#endif
+ if (Colors::openGlAwailable)
+ Colors::openGlRendering = true;
+ else
+ Colors::softwareRendering = true;
+ }
+}
+
+
diff --git a/demos/qtdemo/colors.h b/demos/qtdemo/colors.h
new file mode 100644
index 0000000..58865c6
--- /dev/null
+++ b/demos/qtdemo/colors.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef COLORS_H
+#define COLORS_H
+
+#include <QtGui>
+#include <QBrush>
+
+class Colors
+{
+private:
+ Colors(){};
+
+public:
+ static void parseArgs(int argc, char *argv[]);
+ static void detectSystemResources();
+ static void postConfigure();
+ static void setLowSettings();
+
+ // Colors:
+ static QColor sceneBg1;
+ static QColor sceneBg2;
+ static QColor sceneBg1Line;
+ static QColor paperBg;
+ static QColor menuTextFg;
+ static QColor buttonText;
+ static QColor buttonBgLow;
+ static QColor buttonBgHigh;
+ static QColor tt_green;
+ static QColor fadeOut;
+ static QColor sceneLine;
+ static QColor heading;
+ static QString contentColor;
+ static QString glVersion;
+
+ // Guides:
+ static int stageStartY;
+ static int stageHeight;
+ static int stageStartX;
+ static int stageWidth;
+ static int contentStartY;
+ static int contentHeight;
+
+ // properties:
+ static bool openGlRendering;
+ static bool direct3dRendering;
+ static bool softwareRendering;
+ static bool openGlAwailable;
+ static bool direct3dAwailable;
+ static bool xRenderPresent;
+ static bool noAdapt;
+ static bool noTicker;
+ static bool noRescale;
+ static bool noAnimations;
+ static bool noBlending;
+ static bool noScreenSync;
+ static bool useLoop;
+ static bool noWindowMask;
+ static bool usePixmaps;
+ static bool useEightBitPalette;
+ static bool fullscreen;
+ static bool showBoundingRect;
+ static bool showFps;
+ static bool noTimerUpdate;
+ static bool noTickerMorph;
+ static bool useButtonBalls;
+ static bool adapted;
+ static bool verbose;
+ static bool pause;
+
+ static float animSpeed;
+ static float animSpeedButtons;
+ static float benchmarkFps;
+ static int tickerLetterCount;
+ static int fps;
+ static int menuCount;
+ static float tickerMoveSpeed;
+ static float tickerMorphSpeed;
+ static QString tickerText;
+ static QString rootMenuName;
+
+ // fonts
+ static QFont contentFont();
+ static QFont headingFont();
+ static QFont buttonFont();
+ static QFont tickerFont();
+
+};
+
+#endif // COLORS_H
+
diff --git a/demos/qtdemo/demoitem.cpp b/demos/qtdemo/demoitem.cpp
new file mode 100644
index 0000000..0335bd3
--- /dev/null
+++ b/demos/qtdemo/demoitem.cpp
@@ -0,0 +1,280 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "demoitem.h"
+#include "menumanager.h"
+#include "guide.h"
+#include "colors.h"
+
+QHash<QString, SharedImage *> DemoItem::sharedImageHash;
+QMatrix DemoItem::matrix;
+
+DemoItem::DemoItem(QGraphicsScene *scene, QGraphicsItem *parent) : QGraphicsItem(parent, scene)
+{
+ this->opacity = 1.0;
+ this->locked = false;
+ this->prepared = false;
+ this->neverVisible = false;
+ this->noSubPixeling = false;
+ this->currentAnimation = 0;
+ this->currGuide = 0;
+ this->guideFrame = 0;
+ this->sharedImage = new SharedImage();
+ ++this->sharedImage->refCount;
+}
+
+DemoItem::~DemoItem()
+{
+ if(--this->sharedImage->refCount == 0){
+ if (!this->hashKey.isEmpty())
+ DemoItem::sharedImageHash.remove(this->hashKey);
+ delete this->sharedImage;
+ }
+}
+
+void DemoItem::setNeverVisible(bool never)
+{
+ Q_UNUSED(never);
+/*
+ this->neverVisible = never;
+ if (never){
+ this->setVisible(false);
+ QList<QGraphicsItem *> c = children();
+ for (int i=0; i<c.size(); i++){
+ DemoItem *d = dynamic_cast<DemoItem *>(c[i]); // Don't use dynamic cast because it needs RTTI support.
+ if (d)
+ d->setNeverVisible(true);
+ else{
+ c[i]->setVisible(false);
+ }
+ }
+ }
+*/
+}
+
+void DemoItem::setRecursiveVisible(bool visible){
+ if (visible && this->neverVisible){
+ this->setVisible(false);
+ return;
+ }
+
+ this->setVisible(visible);
+ QList<QGraphicsItem *> c = children();
+ for (int i=0; i<c.size(); i++){
+ // DemoItem *d = dynamic_cast<DemoItem *>(c[i]);
+ // if (d)
+ // d->setRecursiveVisible(visible);
+ // else{
+ c[i]->setVisible(visible);
+ // }
+ }
+}
+
+void DemoItem::useGuide(Guide *guide, float startFrame)
+{
+ this->startFrame = startFrame;
+ this->guideFrame = startFrame;
+ while (this->guideFrame > guide->startLength + guide->length()){
+ if (guide->nextGuide == guide->firstGuide)
+ break;
+
+ guide = guide->nextGuide;
+ }
+ this->currGuide = guide;
+}
+
+void DemoItem::guideAdvance(float distance)
+{
+ this->guideFrame += distance;
+ while (this->guideFrame > this->currGuide->startLength + this->currGuide->length()){
+ this->currGuide = this->currGuide->nextGuide;
+ if (this->currGuide == this->currGuide->firstGuide)
+ this->guideFrame -= this->currGuide->lengthAll();
+ }
+}
+
+void DemoItem::guideMove(float moveSpeed)
+{
+ this->currGuide->guide(this, moveSpeed);
+}
+
+void DemoItem::setPosUsingSheepDog(const QPointF &dest, const QRectF &sceneFence)
+{
+ this->setPos(dest);
+ if (sceneFence.isNull())
+ return;
+
+ // I agree. This is not the optimal way of doing it.
+ // But don't want for use time on it now....
+ float itemWidth = this->boundingRect().width();
+ float itemHeight = this->boundingRect().height();
+ float fenceRight = sceneFence.x() + sceneFence.width();
+ float fenceBottom = sceneFence.y() + sceneFence.height();
+
+ if (this->scenePos().x() < sceneFence.x()) this->moveBy(this->mapFromScene(QPointF(sceneFence.x(), 0)).x(), 0);
+ if (this->scenePos().x() > fenceRight - itemWidth) this->moveBy(this->mapFromScene(QPointF(fenceRight - itemWidth, 0)).x(), 0);
+ if (this->scenePos().y() < sceneFence.y()) this->moveBy(0, this->mapFromScene(QPointF(0, sceneFence.y())).y());
+ if (this->scenePos().y() > fenceBottom - itemHeight) this->moveBy(0, this->mapFromScene(QPointF(0, fenceBottom - itemHeight)).y());
+}
+
+void DemoItem::setGuidedPos(const QPointF &pos)
+{
+ this->guidedPos = pos;
+}
+
+QPointF DemoItem::getGuidedPos()
+{
+ return this->guidedPos;
+}
+
+void DemoItem::switchGuide(Guide *guide)
+{
+ this->currGuide = guide;
+ this->guideFrame = 0;
+}
+
+bool DemoItem::inTransition()
+{
+ if (this->currentAnimation)
+ return this->currentAnimation->running();
+ else
+ return false;
+}
+
+void DemoItem::setMatrix(const QMatrix &matrix)
+{
+ DemoItem::matrix = matrix;
+}
+
+void DemoItem::useSharedImage(const QString &hashKey)
+{
+ this->hashKey = hashKey;
+ if (!sharedImageHash.contains(hashKey))
+ sharedImageHash.insert(hashKey, this->sharedImage);
+ else {
+ if(--this->sharedImage->refCount == 0)
+ delete this->sharedImage;
+ this->sharedImage = sharedImageHash.value(hashKey);
+ ++this->sharedImage->refCount;
+ }
+}
+
+bool DemoItem::validateImage()
+{
+ if ((this->sharedImage->matrix != DemoItem::matrix && !Colors::noRescale) || !(this->sharedImage->image || this->sharedImage->pixmap)){
+ // (Re)create image according to new matrix
+ delete this->sharedImage->image;
+ this->sharedImage->image = 0;
+ delete this->sharedImage->pixmap;
+ this->sharedImage->pixmap = 0;
+ this->sharedImage->matrix = DemoItem::matrix;
+
+ // Let subclass create and draw a new image according to the new matrix
+ QImage *image = this->createImage(Colors::noRescale ? QMatrix() : DemoItem::matrix);
+ if (image){
+ if (Colors::showBoundingRect){
+ // draw red transparent rect
+ QPainter painter(image);
+ painter.fillRect(image->rect(), QColor(255, 0, 0, 50));
+ painter.end();
+ }
+
+ this->sharedImage->unscaledBoundingRect = this->sharedImage->matrix.inverted().mapRect(image->rect());
+ if (Colors::usePixmaps){
+ if (image->isNull())
+ this->sharedImage->pixmap = new QPixmap(1, 1);
+ else
+ this->sharedImage->pixmap = new QPixmap(image->size());
+ this->sharedImage->pixmap->fill(QColor(0, 0, 0, 0));
+ QPainter painter(this->sharedImage->pixmap);
+ painter.drawImage(0, 0, *image);
+ delete image;
+ } else {
+ this->sharedImage->image = image;
+ }
+ return true;
+ } else
+ return false;
+ }
+ return true;
+}
+
+QRectF DemoItem::boundingRect() const
+{
+ const_cast<DemoItem *>(this)->validateImage();
+ return this->sharedImage->unscaledBoundingRect;
+}
+
+void DemoItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+
+ if (this->validateImage()){
+
+ bool wasSmoothPixmapTransform = painter->testRenderHint(QPainter::SmoothPixmapTransform);
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
+
+ if (Colors::noRescale){
+ // Let the painter scale the image for us.
+ // This may degrade both quality and performance
+ if (this->sharedImage->image)
+ painter->drawImage(this->pos(), *this->sharedImage->image);
+ else
+ painter->drawPixmap(this->pos(), *this->sharedImage->pixmap);
+ }
+ else {
+ QMatrix m = painter->worldMatrix();
+ painter->setWorldMatrix(QMatrix());
+ float x = this->noSubPixeling ? qRound(m.dx()) : m.dx();
+ float y = this->noSubPixeling ? qRound(m.dy()) : m.dy();
+ if (this->sharedImage->image)
+ painter->drawImage(QPointF(x, y), *this->sharedImage->image);
+ else
+ painter->drawPixmap(QPointF(x, y), *this->sharedImage->pixmap);
+ }
+
+ if (!wasSmoothPixmapTransform) {
+ painter->setRenderHint(QPainter::SmoothPixmapTransform, false);
+ }
+
+ }
+}
diff --git a/demos/qtdemo/demoitem.h b/demos/qtdemo/demoitem.h
new file mode 100644
index 0000000..e03327b
--- /dev/null
+++ b/demos/qtdemo/demoitem.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEMO_ITEM_H
+#define DEMO_ITEM_H
+
+#include <QtGui>
+
+class DemoItemAnimation;
+class Guide;
+
+class SharedImage
+{
+public:
+ SharedImage() : refCount(0), image(0), pixmap(0){};
+ ~SharedImage()
+ {
+ delete image;
+ delete pixmap;
+ }
+
+ int refCount;
+ QImage *image;
+ QPixmap *pixmap;
+ QMatrix matrix;
+ QRectF unscaledBoundingRect;
+};
+
+class DemoItem : public QGraphicsItem
+{
+
+public:
+ DemoItem(QGraphicsScene *scene = 0, QGraphicsItem *parent = 0);
+ virtual ~DemoItem();
+
+ bool inTransition();
+ virtual void animationStarted(int id = 0){ Q_UNUSED(id); };
+ virtual void animationStopped(int id = 0){ Q_UNUSED(id); };
+ virtual void prepare(){};
+ void setRecursiveVisible(bool visible);
+ void useSharedImage(const QString &hashKey);
+ void setNeverVisible(bool never = true);
+ static void setMatrix(const QMatrix &matrix);
+ virtual QRectF boundingRect() const; // overridden
+ void setPosUsingSheepDog(const QPointF &dest, const QRectF &sceneFence);
+
+ qreal opacity;
+ bool locked;
+ DemoItemAnimation *currentAnimation;
+ bool noSubPixeling;
+
+ // Used if controlled by a guide:
+ void useGuide(Guide *guide, float startFrame = 0);
+ void guideAdvance(float distance);
+ void guideMove(float moveSpeed);
+ void setGuidedPos(const QPointF &position);
+ QPointF getGuidedPos();
+ float startFrame;
+ float guideFrame;
+ Guide *currGuide;
+
+protected:
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option = 0, QWidget *widget = 0); // overridden
+ virtual QImage *createImage(const QMatrix &) const { return 0; };
+ virtual bool collidesWithItem(const QGraphicsItem *, Qt::ItemSelectionMode) const { return false; };
+ bool prepared;
+
+private:
+ SharedImage *sharedImage;
+ QString hashKey;
+ bool neverVisible;
+ bool validateImage();
+
+ // Used if controlled by a guide:
+ void switchGuide(Guide *guide);
+ friend class Guide;
+ QPointF guidedPos;
+
+ // The next static hash is shared amongst all demo items, and
+ // has the purpose of reusing images to save memory and time
+ static QHash<QString, SharedImage *> sharedImageHash;
+ static QMatrix matrix;
+};
+
+#endif // DEMO_ITEM_H
+
diff --git a/demos/qtdemo/demoitemanimation.cpp b/demos/qtdemo/demoitemanimation.cpp
new file mode 100644
index 0000000..92b2d24
--- /dev/null
+++ b/demos/qtdemo/demoitemanimation.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "demoitemanimation.h"
+#include "demoitem.h"
+#include "colors.h"
+
+DemoItemAnimation::DemoItemAnimation(DemoItem *item, INOROUT inOrOut)
+{
+ this->opacityAt0 = 1.0;
+ this->opacityAt1 = 1.0;
+ this->startDelay = 0;
+ this->inOrOut = inOrOut;
+ this->hideOnFinished = false;
+ this->forcePlay = false;
+ this->timeline = new QTimeLine(5000);
+ this->timeline->setFrameRange(0, 2000);
+ this->timeline->setUpdateInterval(int(1000.0/Colors::fps));
+ this->moveOnPlay = false;
+ setTimeLine(this->timeline);
+ setItem(item);
+}
+
+DemoItemAnimation::~DemoItemAnimation()
+{
+ // Do not delete demoitem. It is not
+ // owned by an animation
+ delete this->timeline;
+}
+
+void DemoItemAnimation::prepare()
+{
+ this->demoItem()->prepare();
+}
+
+void DemoItemAnimation::setStartPos(const QPointF &pos){
+ this->startPos = pos;
+}
+
+void DemoItemAnimation::setDuration(int duration)
+{
+ duration = int(duration * Colors::animSpeed);
+ this->timeline->setDuration(duration);
+ this->moveOnPlay = true;
+}
+
+void DemoItemAnimation::setCurrentTime(int ms)
+{
+ this->timeline->setCurrentTime(ms);
+}
+
+bool DemoItemAnimation::notOwnerOfItem()
+{
+ return this != demoItem()->currentAnimation;
+}
+
+void DemoItemAnimation::play(bool fromStart, bool force)
+{
+ this->fromStart = fromStart;
+ this->forcePlay = force;
+
+ QPointF currPos = this->demoItem()->pos();
+
+ // If the item that this animation controls in currently under the
+ // control of another animation, stop that animation first
+ if (this->demoItem()->currentAnimation)
+ this->demoItem()->currentAnimation->timeline->stop();
+ this->demoItem()->currentAnimation = this;
+ this->timeline->stop();
+
+ if (Colors::noAnimations && !this->forcePlay){
+ this->timeline->setCurrentTime(1);
+ this->demoItem()->setPos(this->posAt(1));
+ }
+ else{
+ if (this->demoItem()->isVisible())
+ // If the item is already visible, start the animation from
+ // the items current position rather than from start.
+ this->setPosAt(0.0, currPos);
+ else
+ this->setPosAt(0.0, this->startPos);
+
+ if (this->fromStart){
+ this->timeline->setCurrentTime(0);
+ this->demoItem()->setPos(this->posAt(0));
+ }
+ }
+
+ if (this->inOrOut == ANIM_IN)
+ this->demoItem()->setRecursiveVisible(true);
+
+ if (this->startDelay){
+ QTimer::singleShot(this->startDelay, this, SLOT(playWithoutDelay()));
+ return;
+ }
+ else
+ this->playWithoutDelay();
+}
+
+void DemoItemAnimation::playWithoutDelay()
+{
+ if (this->moveOnPlay && !(Colors::noAnimations && !this->forcePlay))
+ this->timeline->start();
+ this->demoItem()->animationStarted(this->inOrOut);
+}
+
+void DemoItemAnimation::stop(bool reset)
+{
+ this->timeline->stop();
+ if (reset)
+ this->demoItem()->setPos(this->posAt(0));
+ if (this->hideOnFinished && !this->moveOnPlay)
+ this->demoItem()->setRecursiveVisible(false);
+ this->demoItem()->animationStopped(this->inOrOut);
+}
+
+void DemoItemAnimation::setRepeat(int nr)
+{
+ this->timeline->setLoopCount(nr);
+}
+
+void DemoItemAnimation::playReverse()
+{
+}
+
+bool DemoItemAnimation::running()
+{
+ return (this->timeLine()->state() == QTimeLine::Running);
+}
+
+bool DemoItemAnimation::runningOrItemLocked()
+{
+ return (this->running() || this->demoItem()->locked);
+}
+
+void DemoItemAnimation::lockItem(bool state)
+{
+ this->demoItem()->locked = state;
+}
+
+DemoItem *DemoItemAnimation::demoItem()
+{
+ return (DemoItem *) this->item();
+}
+
+void DemoItemAnimation::setOpacityAt0(qreal opacity)
+{
+ this->opacityAt0 = opacity;
+}
+
+void DemoItemAnimation::setOpacityAt1(qreal opacity)
+{
+ this->opacityAt1 = opacity;
+}
+
+void DemoItemAnimation::setOpacity(qreal step)
+{
+ DemoItem *demoItem = (DemoItem *) item();
+ demoItem->opacity = this->opacityAt0 + step * step * step * (this->opacityAt1 - this->opacityAt0);
+}
+
+void DemoItemAnimation::afterAnimationStep(qreal step)
+{
+ if (step == 1.0f){
+ if (this->timeline->loopCount() > 0){
+ // animation finished.
+ if (this->hideOnFinished)
+ this->demoItem()->setRecursiveVisible(false);
+ this->demoItem()->animationStopped(this->inOrOut);
+ }
+ } else if (Colors::noAnimations && !this->forcePlay){
+ // The animation is not at end, but
+ // the animations should not play, so go to end.
+ this->setStep(1.0f); // will make this method being called recursive.
+ }
+}
+
+
+
+
+
diff --git a/demos/qtdemo/demoitemanimation.h b/demos/qtdemo/demoitemanimation.h
new file mode 100644
index 0000000..ad89ada
--- /dev/null
+++ b/demos/qtdemo/demoitemanimation.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEMO_ITEM_ANIMATION_H
+#define DEMO_ITEM_ANIMATION_H
+
+#include <QtCore>
+#include <QtGui>
+
+class DemoItem;
+
+class DemoItemAnimation : public QGraphicsItemAnimation
+{
+ Q_OBJECT
+
+public:
+ enum INOROUT {ANIM_IN, ANIM_OUT, ANIM_UNSPECIFIED};
+
+ DemoItemAnimation(DemoItem *item, INOROUT inOrOut = ANIM_UNSPECIFIED);
+ virtual ~DemoItemAnimation();
+
+ virtual void play(bool fromStart = true, bool force = false);
+ virtual void playReverse();
+ virtual void stop(bool reset = true);
+ virtual void setRepeat(int nr = 0);
+
+ void setDuration(int duration);
+ void setDuration(float duration){ setDuration(int(duration)); };
+ void setOpacityAt0(qreal opacity);
+ void setOpacityAt1(qreal opacity);
+ void setOpacity(qreal step);
+ void setCurrentTime(int ms);
+ void setStartPos(const QPointF &pos);
+ bool notOwnerOfItem();
+
+ bool running();
+ bool runningOrItemLocked();
+ void lockItem(bool state);
+ void prepare();
+
+ DemoItem *demoItem();
+
+ virtual void afterAnimationStep(qreal step); // overridden
+
+ QTimeLine *timeline;
+ qreal opacityAt0;
+ qreal opacityAt1;
+ int startDelay;
+ QPointF startPos;
+ bool hideOnFinished;
+ bool moveOnPlay;
+ bool forcePlay;
+ bool fromStart;
+ INOROUT inOrOut;
+
+private slots:
+ virtual void playWithoutDelay();
+};
+
+#endif // DEMO_ITEM_ANIMATION_H
+
+
+
diff --git a/demos/qtdemo/demoscene.cpp b/demos/qtdemo/demoscene.cpp
new file mode 100644
index 0000000..29b73d3
--- /dev/null
+++ b/demos/qtdemo/demoscene.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "demoscene.h"
+
+void DemoScene::drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[], QWidget *widget)
+{
+ for (int i=0; i<numItems; ++i) {
+ painter->save();
+ painter->setMatrix(items[i]->sceneMatrix(), true);
+ items[i]->paint(painter, &options[i], widget);
+ painter->restore();
+ }
+}
+
+
diff --git a/demos/qtdemo/demoscene.h b/demos/qtdemo/demoscene.h
new file mode 100644
index 0000000..e4838c7
--- /dev/null
+++ b/demos/qtdemo/demoscene.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAIN_VIEW_H
+#define MAIN_VIEW_H
+
+#include <QtGui>
+
+class DemoScene : public QGraphicsScene
+{
+public:
+ DemoScene(QObject *parent) : QGraphicsScene(parent){};
+
+protected:
+ void drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[], QWidget *widget);
+};
+
+#endif // MAIN_VIEW_H
+
diff --git a/demos/qtdemo/demotextitem.cpp b/demos/qtdemo/demotextitem.cpp
new file mode 100644
index 0000000..cd549fc
--- /dev/null
+++ b/demos/qtdemo/demotextitem.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "demotextitem.h"
+#include "colors.h"
+
+DemoTextItem::DemoTextItem(const QString &text, const QFont &font, const QColor &textColor,
+ float textWidth, QGraphicsScene *scene, QGraphicsItem *parent, TYPE type, const QColor &bgColor)
+ : DemoItem(scene, parent)
+{
+ this->type = type;
+ this->text = text;
+ this->font = font;
+ this->textColor = textColor;
+ this->bgColor = bgColor;
+ this->textWidth = textWidth;
+ this->noSubPixeling = true;
+}
+
+void DemoTextItem::setText(const QString &text)
+{
+ this->text = text;
+ this->update();
+}
+
+QImage *DemoTextItem::createImage(const QMatrix &matrix) const
+{
+ if (this->type == DYNAMIC_TEXT)
+ return 0;
+
+ float sx = qMin(matrix.m11(), matrix.m22());
+ float sy = matrix.m22() < sx ? sx : matrix.m22();
+
+ QGraphicsTextItem textItem(0, 0);
+ textItem.setHtml(this->text);
+ textItem.setTextWidth(this->textWidth);
+ textItem.setFont(this->font);
+ textItem.setDefaultTextColor(this->textColor);
+ textItem.document()->setDocumentMargin(2);
+
+ float w = textItem.boundingRect().width();
+ float h = textItem.boundingRect().height();
+ QImage *image = new QImage(int(w * sx), int(h * sy), QImage::Format_ARGB32_Premultiplied);
+ image->fill(QColor(0, 0, 0, 0).rgba());
+ QPainter painter(image);
+ painter.scale(sx, sy);
+ QStyleOptionGraphicsItem style;
+ textItem.paint(&painter, &style, 0);
+ return image;
+}
+
+
+void DemoTextItem::animationStarted(int)
+{
+ this->noSubPixeling = false;
+}
+
+
+void DemoTextItem::animationStopped(int)
+{
+ this->noSubPixeling = true;
+}
+
+QRectF DemoTextItem::boundingRect() const
+
+{
+ if (this->type == STATIC_TEXT)
+ return DemoItem::boundingRect();
+ return QRectF(0, 0, 50, 20); // Sorry for using magic number
+}
+
+
+void DemoTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+
+ if (this->type == STATIC_TEXT) {
+ DemoItem::paint(painter, option, widget);
+ return;
+ }
+
+ painter->setPen(this->textColor);
+ painter->drawText(0, 0, this->text);
+}
diff --git a/demos/qtdemo/demotextitem.h b/demos/qtdemo/demotextitem.h
new file mode 100644
index 0000000..679e3fb
--- /dev/null
+++ b/demos/qtdemo/demotextitem.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEMO_TEXT_ITEM_H
+#define DEMO_TEXT_ITEM_H
+
+#include <QtGui>
+#include "demoitem.h"
+
+class DemoTextItem : public DemoItem
+{
+public:
+ enum TYPE {STATIC_TEXT, DYNAMIC_TEXT};
+
+ DemoTextItem(const QString &text, const QFont &font, const QColor &textColor,
+ float textWidth, QGraphicsScene *scene = 0, QGraphicsItem *parent = 0, TYPE type = STATIC_TEXT, const QColor &bgColor = QColor());
+ void setText(const QString &text);
+ QRectF boundingRect() const; // overridden
+ void animationStarted(int id = 0);
+ void animationStopped(int id = 0);
+
+protected:
+ virtual QImage *createImage(const QMatrix &matrix) const; // overridden
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option = 0, QWidget *widget = 0); // overridden
+
+private:
+ float textWidth;
+ QString text;
+ QFont font;
+ QColor textColor;
+ QColor bgColor;
+ TYPE type;
+};
+
+#endif // DEMO_TEXT_ITEM_H
+
diff --git a/demos/qtdemo/dockitem.cpp b/demos/qtdemo/dockitem.cpp
new file mode 100644
index 0000000..7f26f04
--- /dev/null
+++ b/demos/qtdemo/dockitem.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "dockitem.h"
+#include "colors.h"
+
+DockItem::DockItem(ORIENTATION orien, qreal x, qreal y, qreal width, qreal length, QGraphicsScene *scene, QGraphicsItem *parent)
+ : DemoItem(scene, parent)
+{
+ this->orientation = orien;
+ this->width = width;
+ this->length = length;
+ this->setPos(x, y);
+ this->setZValue(40);
+ this->setupPixmap();
+}
+
+void DockItem::setupPixmap()
+{
+ this->pixmap = new QPixmap(int(this->boundingRect().width()), int(this->boundingRect().height()));
+ this->pixmap->fill(QColor(0, 0, 0, 0));
+ QPainter painter(this->pixmap);
+ // create brush:
+ QColor background = Colors::sceneBg1;
+ QLinearGradient brush(0, 0, 0, this->boundingRect().height());
+ brush.setSpread(QGradient::PadSpread);
+
+ if (this->orientation == DOWN){
+ brush.setColorAt(0.0, background);
+ brush.setColorAt(0.2, background);
+ background.setAlpha(0);
+ brush.setColorAt(1.0, background);
+ }
+ else
+ if (this->orientation == UP){
+ brush.setColorAt(1.0, background);
+ brush.setColorAt(0.8, background);
+ background.setAlpha(0);
+ brush.setColorAt(0.0, background);
+ }
+ else
+ qWarning("DockItem doesn't support the orientation given!");
+
+ painter.fillRect(0, 0, int(this->boundingRect().width()), int(this->boundingRect().height()), brush);
+
+}
+
+DockItem::~DockItem()
+{
+ delete this->pixmap;
+}
+
+QRectF DockItem::boundingRect() const
+{
+ if (this->orientation == UP || this->orientation == DOWN)
+ return QRectF(0, 0, this->length, this->width);
+ else
+ return QRectF(0, 0, this->width, this->length);
+}
+
+void DockItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+
+ painter->drawPixmap(0, 0, *this->pixmap);
+}
+
+
+
diff --git a/demos/qtdemo/dockitem.h b/demos/qtdemo/dockitem.h
new file mode 100644
index 0000000..13473a3
--- /dev/null
+++ b/demos/qtdemo/dockitem.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DOCK_ITEM_H
+#define DOCK_ITEM_H
+
+#include <QtGui>
+#include "demoitem.h"
+
+class DockItem : public DemoItem
+{
+public:
+ enum ORIENTATION {UP, DOWN, LEFT, RIGHT};
+
+ DockItem(ORIENTATION orien, qreal x, qreal y, qreal width, qreal length, QGraphicsScene *scene = 0, QGraphicsItem *parent = 0);
+ virtual ~DockItem();
+
+ virtual QRectF boundingRect() const; // overridden
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); // overridden
+
+ qreal length;
+ qreal width;
+ ORIENTATION orientation;
+
+private:
+ void setupPixmap();
+ QPixmap *pixmap;
+};
+
+#endif // DOCK_ITEM_H
+
diff --git a/demos/qtdemo/examplecontent.cpp b/demos/qtdemo/examplecontent.cpp
new file mode 100644
index 0000000..a568b8c
--- /dev/null
+++ b/demos/qtdemo/examplecontent.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "examplecontent.h"
+#include "colors.h"
+#include "menumanager.h"
+#include "imageitem.h"
+#include "headingitem.h"
+
+ExampleContent::ExampleContent(const QString &name, QGraphicsScene *scene, QGraphicsItem *parent)
+ : DemoItem(scene, parent)
+{
+ this->name = name;
+ this->heading = 0;
+ this->description = 0;
+ this->screenshot = 0;
+}
+
+void ExampleContent::prepare()
+{
+ if (!this->prepared){
+ this->prepared = true;
+ this->createContent();
+ }
+}
+
+void ExampleContent::animationStopped(int id)
+{
+ if (id == DemoItemAnimation::ANIM_OUT){
+ // Free up some memory:
+ delete this->heading;
+ delete this->description;
+ delete this->screenshot;
+ this->heading = 0;
+ this->description = 0;
+ this->screenshot = 0;
+ this->prepared = false;
+ }
+}
+
+QString ExampleContent::loadDescription()
+{
+ QByteArray ba = MenuManager::instance()->getHtml(this->name);
+
+ QDomDocument exampleDoc;
+ exampleDoc.setContent(ba, false);
+
+ QDomNodeList paragraphs = exampleDoc.elementsByTagName("p");
+ if (paragraphs.length() < 1 && Colors::verbose)
+ qDebug() << "- ExampleContent::loadDescription(): Could not load description:" << MenuManager::instance()->info[this->name]["docfile"];
+ QString description = Colors::contentColor + QLatin1String("Could not load description. Ensure that the documentation for Qt is built.");
+ for (int p = 0; p < int(paragraphs.length()); ++p) {
+ description = this->extractTextFromParagraph(paragraphs.item(p));
+ if (this->isSummary(description)) {
+ break;
+ }
+ }
+ return Colors::contentColor + description;
+}
+
+bool ExampleContent::isSummary(const QString &text)
+{
+ return (!text.contains("[") &&
+ text.indexOf(QRegExp(QString("(In )?((The|This) )?(%1 )?.*(tutorial|example|demo|application)").arg(this->name), Qt::CaseInsensitive)) != -1);
+}
+
+QString ExampleContent::extractTextFromParagraph(const QDomNode &parentNode)
+{
+ QString description;
+ QDomNode node = parentNode.firstChild();
+
+ while (!node.isNull()) {
+ QString beginTag;
+ QString endTag;
+ if (node.isText())
+ description += Colors::contentColor + node.nodeValue();
+ else if (node.hasChildNodes()) {
+ if (node.nodeName() == "b") {
+ beginTag = "<b>";
+ endTag = "</b>";
+ } else if (node.nodeName() == "a") {
+ beginTag = Colors::contentColor;
+ endTag = "</font>";
+ } else if (node.nodeName() == "i") {
+ beginTag = "<i>";
+ endTag = "</i>";
+ } else if (node.nodeName() == "tt") {
+ beginTag = "<tt>";
+ endTag = "</tt>";
+ }
+ description += beginTag + this->extractTextFromParagraph(node) + endTag;
+ }
+ node = node.nextSibling();
+ }
+
+ return description;
+}
+
+void ExampleContent::createContent()
+{
+ // Create the items:
+ this->heading = new HeadingItem(this->name, this->scene(), this);
+ this->description = new DemoTextItem(this->loadDescription(), Colors::contentFont(),
+ Colors::heading, 500, this->scene(), this);
+ int imgHeight = 340 - int(this->description->boundingRect().height()) + 50;
+ this->screenshot = new ImageItem(QImage::fromData(MenuManager::instance()->getImage(this->name)),
+ 550, imgHeight, this->scene(), this);
+
+ // Place the items on screen:
+ this->heading->setPos(0, 3);
+ this->description->setPos(0, this->heading->pos().y() + this->heading->boundingRect().height() + 10);
+ this->screenshot->setPos(0, this->description->pos().y() + this->description->boundingRect().height() + 10);
+}
+
+QRectF ExampleContent::boundingRect() const
+{
+ return QRectF(0, 0, 500, 100);
+}
+
+
diff --git a/demos/qtdemo/examplecontent.h b/demos/qtdemo/examplecontent.h
new file mode 100644
index 0000000..850d64b
--- /dev/null
+++ b/demos/qtdemo/examplecontent.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CONTENT_ITEM_H
+#define CONTENT_ITEM_H
+
+#include <QtGui>
+#include <QtXml>
+#include "demoitem.h"
+
+class HeadingItem;
+class DemoTextItem;
+class ImageItem;
+
+class ExampleContent : public DemoItem
+{
+
+public:
+ ExampleContent(const QString &name, QGraphicsScene *scene = 0, QGraphicsItem *parent = 0);
+
+ virtual QRectF boundingRect() const;
+ virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0){};
+ void animationStopped(int id);
+ void prepare();
+
+private:
+ QString name;
+ HeadingItem *heading;
+ DemoTextItem *description;
+ ImageItem *screenshot;
+
+ QString loadDescription();
+ QString extractTextFromParagraph(const QDomNode &parentNode);
+ bool isSummary(const QString &text);
+ void createContent();
+};
+
+#endif // CONTENT_ITEM_H
+
diff --git a/demos/qtdemo/guide.cpp b/demos/qtdemo/guide.cpp
new file mode 100644
index 0000000..1f3c355
--- /dev/null
+++ b/demos/qtdemo/guide.cpp
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <cmath>
+#include "guide.h"
+#include "colors.h"
+
+Guide::Guide(Guide *follows)
+{
+ this->scaleX = 1.0;
+ this->scaleY = 1.0;
+
+ if (follows){
+ while (follows->nextGuide != follows->firstGuide) // append to end
+ follows = follows->nextGuide;
+
+ follows->nextGuide = this;
+ this->prevGuide = follows;
+ this->firstGuide = follows->firstGuide;
+ this->nextGuide = follows->firstGuide;
+ this->startLength = int(follows->startLength + follows->length()) + 1;
+ }
+ else{
+ this->prevGuide = this;
+ this->firstGuide = this;
+ this->nextGuide = this;
+ this->startLength = 0;
+ }
+}
+
+void Guide::setScale(float scaleX, float scaleY, bool all)
+{
+ this->scaleX = scaleX;
+ this->scaleY = scaleY;
+
+ if (all){
+ Guide *next = this->nextGuide;
+ while(next != this){
+ next->scaleX = scaleX;
+ next->scaleY = scaleY;
+ next = next->nextGuide;
+ }
+ }
+}
+
+void Guide::setFence(const QRectF &fence, bool all)
+{
+ this->fence = fence;
+
+ if (all){
+ Guide *next = this->nextGuide;
+ while(next != this){
+ next->fence = fence;
+ next = next->nextGuide;
+ }
+ }
+}
+
+Guide::~Guide()
+{
+ if (this != this->nextGuide && this->nextGuide != this->firstGuide)
+ delete this->nextGuide;
+}
+
+float Guide::lengthAll()
+{
+ float len = length();
+ Guide *next = this->nextGuide;
+ while(next != this){
+ len += next->length();
+ next = next->nextGuide;
+ }
+ return len;
+}
+
+void Guide::move(DemoItem *item, QPointF &dest, float moveSpeed)
+{
+ QLineF walkLine(item->getGuidedPos(), dest);
+ if (moveSpeed >= 0 && walkLine.length() > moveSpeed){
+ // The item is too far away from it's destination point.
+ // So we choose to move it towards it instead.
+ float dx = walkLine.dx();
+ float dy = walkLine.dy();
+
+ if (qAbs(dx) > qAbs(dy)){
+ // walk along x-axis
+ if (dx != 0){
+ float d = moveSpeed * dy / qAbs(dx);
+ float s = dx > 0 ? moveSpeed : -moveSpeed;
+ dest.setX(item->getGuidedPos().x() + s);
+ dest.setY(item->getGuidedPos().y() + d);
+ }
+ }
+ else{
+ // walk along y-axis
+ if (dy != 0){
+ float d = moveSpeed * dx / qAbs(dy);
+ float s = dy > 0 ? moveSpeed : -moveSpeed;
+ dest.setX(item->getGuidedPos().x() + d);
+ dest.setY(item->getGuidedPos().y() + s);
+ }
+ }
+ }
+
+ item->setGuidedPos(dest);
+}
diff --git a/demos/qtdemo/guide.h b/demos/qtdemo/guide.h
new file mode 100644
index 0000000..51ce6c3
--- /dev/null
+++ b/demos/qtdemo/guide.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GUIDE_H
+#define GUIDE_H
+
+#include "demoitem.h"
+
+class Guide
+{
+public:
+ Guide(Guide *follows = 0);
+ virtual ~Guide();
+
+ virtual void guide(DemoItem *item, float moveSpeed) = 0;
+ void move(DemoItem *item, QPointF &dest, float moveSpeed);
+ virtual QPointF startPos(){ return QPointF(0, 0); };
+ virtual QPointF endPos(){ return QPointF(0, 0); };
+ virtual float length(){ return 1; };
+ float lengthAll();
+
+ void setScale(float scaleX, float scaleY, bool all = true);
+ void setFence(const QRectF &fence, bool all = true);
+
+ int startLength;
+ Guide *nextGuide;
+ Guide *firstGuide;
+ Guide *prevGuide;
+ float scaleX;
+ float scaleY;
+ QRectF fence;
+};
+
+#endif // GUIDE_H
+
diff --git a/demos/qtdemo/guidecircle.cpp b/demos/qtdemo/guidecircle.cpp
new file mode 100644
index 0000000..98328dc
--- /dev/null
+++ b/demos/qtdemo/guidecircle.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "guidecircle.h"
+
+static float PI2 = 2*3.1415f;
+
+GuideCircle::GuideCircle(const QRectF &rect, float startAngle, float span, DIRECTION dir, Guide *follows) : Guide(follows)
+{
+ this->radiusX = rect.width() / 2.0;
+ this->radiusY = rect.height() / 2.0;
+ this->posX = rect.topLeft().x();
+ this->posY = rect.topLeft().y();
+ this->spanRad = span * PI2 / -360.0;
+ if (dir == CCW){
+ this->startAngleRad = startAngle * PI2 / -360.0;
+ this->endAngleRad = startAngleRad + spanRad;
+ this->stepAngleRad = this->spanRad / this->length();
+ }
+ else{
+ this->startAngleRad = spanRad + (startAngle * PI2 / -360.0);
+ this->endAngleRad = startAngle * PI2 / -360.0;
+ this->stepAngleRad = -this->spanRad / this->length();
+ }
+}
+
+float GuideCircle::length()
+{
+ return qAbs(this->radiusX * spanRad);
+}
+
+QPointF GuideCircle::startPos()
+{
+ return QPointF((posX + radiusX + radiusX * cos(startAngleRad)) * scaleX,
+ (posY + radiusY + radiusY * sin(startAngleRad)) * scaleY);
+}
+
+QPointF GuideCircle::endPos()
+{
+ return QPointF((posX + radiusX + radiusX * cos(endAngleRad)) * scaleX,
+ (posY + radiusY + radiusY * sin(endAngleRad)) * scaleY);
+}
+
+void GuideCircle::guide(DemoItem *item, float moveSpeed)
+{
+ float frame = item->guideFrame - this->startLength;
+ QPointF end((posX + radiusX + radiusX * cos(startAngleRad + (frame * stepAngleRad))) * scaleX,
+ (posY + radiusY + radiusY * sin(startAngleRad + (frame * stepAngleRad))) * scaleY);
+ this->move(item, end, moveSpeed);
+}
diff --git a/demos/qtdemo/guidecircle.h b/demos/qtdemo/guidecircle.h
new file mode 100644
index 0000000..2179527
--- /dev/null
+++ b/demos/qtdemo/guidecircle.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GUIDECIRCLE_H
+#define GUIDECIRCLE_H
+
+#include "guide.h"
+#include "demoitem.h"
+
+class GuideCircle : public Guide
+{
+public:
+ enum DIRECTION {CW = 1, CCW = -1};
+
+ GuideCircle(const QRectF &rect, float startAngle = 0, float span = 360, DIRECTION dir = CCW, Guide *follows = 0);
+
+ void guide(DemoItem *item, float moveSpeed); // overridden
+ QPointF startPos();
+ QPointF endPos();
+ float length();
+
+private:
+ float posX;
+ float posY;
+ float radiusX;
+ float radiusY;
+ float startAngleRad;
+ float endAngleRad;
+ float spanRad;
+ float stepAngleRad;
+};
+
+#endif // GUIDECIRCLE_H
+
diff --git a/demos/qtdemo/guideline.cpp b/demos/qtdemo/guideline.cpp
new file mode 100644
index 0000000..ac01339
--- /dev/null
+++ b/demos/qtdemo/guideline.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "guideline.h"
+#include <cmath>
+
+GuideLine::GuideLine(const QLineF &line, Guide *follows) : Guide(follows)
+{
+ this->line = line;
+}
+
+GuideLine::GuideLine(const QPointF &end, Guide *follows) : Guide(follows)
+{
+ if (follows)
+ this->line = QLineF(prevGuide->endPos(), end);
+ else
+ this->line = QLineF(QPointF(0, 0), end);
+}
+
+float GuideLine::length()
+{
+ return line.length();
+}
+
+QPointF GuideLine::startPos()
+{
+ return QPointF(this->line.p1().x() * scaleX, this->line.p1().y() * scaleY);
+}
+
+QPointF GuideLine::endPos()
+{
+ return QPointF(this->line.p2().x() * scaleX, this->line.p2().y() * scaleY);
+}
+
+void GuideLine::guide(DemoItem *item, float moveSpeed)
+{
+ float frame = item->guideFrame - this->startLength;
+ float endX = (this->line.p1().x() + (frame * this->line.dx() / this->length())) * scaleX;
+ float endY = (this->line.p1().y() + (frame * this->line.dy() / this->length())) * scaleY;
+ QPointF pos(endX, endY);
+ this->move(item, pos, moveSpeed);
+}
+
diff --git a/demos/qtdemo/guideline.h b/demos/qtdemo/guideline.h
new file mode 100644
index 0000000..93daaa8
--- /dev/null
+++ b/demos/qtdemo/guideline.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GUIDELINE_H
+#define GUIDELINE_H
+
+#include "guide.h"
+#include "demoitem.h"
+
+class GuideLine : public Guide
+{
+public:
+ GuideLine(const QLineF &line, Guide *follows = 0);
+ GuideLine(const QPointF &end, Guide *follows = 0);
+
+ void guide(DemoItem *item, float moveSpeed); // overridden
+ QPointF startPos();
+ QPointF endPos();
+ float length();
+
+private:
+ QLineF line;
+
+};
+
+#endif // GUIDELINE_H
+
diff --git a/demos/qtdemo/headingitem.cpp b/demos/qtdemo/headingitem.cpp
new file mode 100644
index 0000000..80a255a
--- /dev/null
+++ b/demos/qtdemo/headingitem.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "headingitem.h"
+#include "colors.h"
+
+HeadingItem::HeadingItem(const QString &text, QGraphicsScene *scene, QGraphicsItem *parent)
+ : DemoItem(scene, parent)
+{
+ this->text = text;
+ this->noSubPixeling = true;
+}
+
+QImage *HeadingItem::createImage(const QMatrix &matrix) const
+{
+ float sx = qMin(matrix.m11(), matrix.m22());
+ float sy = matrix.m22() < sx ? sx : matrix.m22();
+ QFontMetrics fm(Colors::headingFont());
+
+ float w = fm.width(this->text) + 1;
+ float h = fm.height();
+ float xShadow = 3.0f;
+ float yShadow = 3.0f;
+
+ QImage *image = new QImage(int((w + xShadow) * sx), int((h + yShadow) * sy), QImage::Format_ARGB32_Premultiplied);
+ image->fill(QColor(0, 0, 0, 0).rgba());
+ QPainter painter(image);
+ painter.setFont(Colors::headingFont());
+ painter.scale(sx, sy);
+
+ //draw shadow
+ QLinearGradient brush_shadow(xShadow, yShadow, w, yShadow);
+ brush_shadow.setSpread(QLinearGradient::PadSpread);
+ if (Colors::useEightBitPalette)
+ brush_shadow.setColorAt(0.0f, QColor(0, 0, 0));
+ else
+ brush_shadow.setColorAt(0.0f, QColor(0, 0, 0, 100));
+ QPen pen_shadow;
+ pen_shadow.setBrush(brush_shadow);
+ painter.setPen(pen_shadow);
+ painter.drawText(int(xShadow), int(yShadow), int(w), int(h), Qt::AlignLeft, this->text);
+
+ // draw text
+ QLinearGradient brush_text(0, 0, w, w);
+ brush_text.setSpread(QLinearGradient::PadSpread);
+ brush_text.setColorAt(0.0f, QColor(255, 255, 255));
+ brush_text.setColorAt(0.2f, QColor(255, 255, 255));
+ brush_text.setColorAt(0.5f, QColor(190, 190, 190));
+ QPen pen_text;
+ pen_text.setBrush(brush_text);
+ painter.setPen(pen_text);
+ painter.drawText(0, 0, int(w), int(h), Qt::AlignLeft, this->text);
+ return image;
+}
+
+
+void HeadingItem::animationStarted(int)
+{
+ this->noSubPixeling = false;
+}
+
+
+void HeadingItem::animationStopped(int)
+{
+ this->noSubPixeling = true;
+}
diff --git a/demos/qtdemo/headingitem.h b/demos/qtdemo/headingitem.h
new file mode 100644
index 0000000..a5cb997
--- /dev/null
+++ b/demos/qtdemo/headingitem.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HEADING_ITEM_H
+#define HEADING_ITEM_H
+
+#include <QtGui>
+#include "demoitem.h"
+
+class HeadingItem : public DemoItem
+{
+public:
+ HeadingItem(const QString &text, QGraphicsScene *scene = 0, QGraphicsItem *parent = 0);
+ void animationStarted(int id = 0);
+ void animationStopped(int id = 0);
+
+protected:
+ virtual QImage *createImage(const QMatrix &matrix) const; // overridden
+
+private:
+ QString text;
+};
+
+#endif // HEADING_ITEM_H
+
diff --git a/demos/qtdemo/imageitem.cpp b/demos/qtdemo/imageitem.cpp
new file mode 100644
index 0000000..e556011
--- /dev/null
+++ b/demos/qtdemo/imageitem.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "imageitem.h"
+#include "colors.h"
+
+ImageItem::ImageItem(const QImage &image, int maxWidth, int maxHeight, QGraphicsScene *scene,
+ QGraphicsItem *parent, bool adjustSize, float scale) : DemoItem(scene, parent)
+{
+ this->image = image;
+ this->maxWidth = maxWidth;
+ this->maxHeight = maxHeight;
+ this->adjustSize = adjustSize;
+ this->scale = scale;
+}
+
+QImage *ImageItem::createImage(const QMatrix &matrix) const
+{
+ QImage *original = new QImage(image);
+ if (original->isNull()){
+ return original; // nothing we can do about it...
+ }
+
+ QPoint size = matrix.map(QPoint(this->maxWidth, this->maxHeight));
+ float w = size.x(); // x, y is the used as width, height
+ float h = size.y();
+
+ // Optimization: if image is smaller than maximum allowed size, just return the loaded image
+ if (original->size().height() <= h && original->size().width() <= w && !this->adjustSize && this->scale == 1)
+ return original;
+
+ // Calculate what the size of the final image will be:
+ w = qMin(w, float(original->size().width()) * this->scale);
+ h = qMin(h, float(original->size().height()) * this->scale);
+
+ float adjustx = 1.0f;
+ float adjusty = 1.0f;
+ if (this->adjustSize){
+ adjustx = qMin(matrix.m11(), matrix.m22());
+ adjusty = matrix.m22() < adjustx ? adjustx : matrix.m22();
+ w *= adjustx;
+ h *= adjusty;
+ }
+
+ // Create a new image with correct size, and draw original on it
+ QImage *image = new QImage(int(w+2), int(h+2), QImage::Format_ARGB32_Premultiplied);
+ image->fill(QColor(0, 0, 0, 0).rgba());
+ QPainter painter(image);
+ painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ if (this->adjustSize)
+ painter.scale(adjustx, adjusty);
+ if (this->scale != 1)
+ painter.scale(this->scale, this->scale);
+ painter.drawImage(0, 0, *original);
+
+ if (!this->adjustSize){
+ // Blur out edges
+ int blur = 30;
+ if (h < original->height()){
+ QLinearGradient brush1(0, h - blur, 0, h);
+ brush1.setSpread(QGradient::PadSpread);
+ brush1.setColorAt(0.0, QColor(0, 0, 0, 0));
+ brush1.setColorAt(1.0, Colors::sceneBg1);
+ painter.fillRect(0, int(h) - blur, original->width(), int(h), brush1);
+ }
+ if (w < original->width()){
+ QLinearGradient brush2(w - blur, 0, w, 0);
+ brush2.setSpread(QGradient::PadSpread);
+ brush2.setColorAt(0.0, QColor(0, 0, 0, 0));
+ brush2.setColorAt(1.0, Colors::sceneBg1);
+ painter.fillRect(int(w) - blur, 0, int(w), original->height(), brush2);
+ }
+ }
+ delete original;
+ return image;
+}
diff --git a/demos/qtdemo/imageitem.h b/demos/qtdemo/imageitem.h
new file mode 100644
index 0000000..e73079a
--- /dev/null
+++ b/demos/qtdemo/imageitem.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef IMAGE_ITEM_H
+#define IMAGE_ITEM_H
+
+#include <QtGui>
+#include "demoitem.h"
+
+class ImageItem : public DemoItem
+{
+public:
+ ImageItem(const QImage &image, int maxWidth, int maxHeight, QGraphicsScene *scene = 0, QGraphicsItem *parent = 0,
+ bool adjustSize = false, float scale = 1.0f);
+
+ bool adjustSize;
+ float scale;
+protected:
+ QImage *createImage(const QMatrix &matrix) const;
+
+private:
+ QImage image;
+ int maxWidth;
+ int maxHeight;
+};
+
+#endif // DOCK_ITEM_H
+
diff --git a/demos/qtdemo/images/demobg.png b/demos/qtdemo/images/demobg.png
new file mode 100755
index 0000000..3280afa
--- /dev/null
+++ b/demos/qtdemo/images/demobg.png
Binary files differ
diff --git a/demos/qtdemo/images/qtlogo_small.png b/demos/qtdemo/images/qtlogo_small.png
new file mode 100644
index 0000000..21b17df
--- /dev/null
+++ b/demos/qtdemo/images/qtlogo_small.png
Binary files differ
diff --git a/demos/qtdemo/images/trolltech-logo.png b/demos/qtdemo/images/trolltech-logo.png
new file mode 100644
index 0000000..186c69c
--- /dev/null
+++ b/demos/qtdemo/images/trolltech-logo.png
Binary files differ
diff --git a/demos/qtdemo/itemcircleanimation.cpp b/demos/qtdemo/itemcircleanimation.cpp
new file mode 100644
index 0000000..fff52bb
--- /dev/null
+++ b/demos/qtdemo/itemcircleanimation.cpp
@@ -0,0 +1,507 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "itemcircleanimation.h"
+#include "demoitemanimation.h"
+#include "colors.h"
+#include "menumanager.h"
+#include "mainwindow.h"
+#include "menumanager.h"
+
+static QGraphicsScene *sscene;
+
+//////////////////// POST EFFECT STUFF ////////////////////////////////////////
+
+class TickerPostEffect
+{
+public:
+ virtual ~TickerPostEffect(){};
+ virtual void tick(float){};
+ virtual void transform(DemoItem *, QPointF &){};
+};
+
+class PostRotateXY : public TickerPostEffect
+{
+public:
+ float currRotX, currRotY;
+ float speedx, speedy, curvx, curvy;
+
+ PostRotateXY(float speedx, float speedy, float curvx, float curvy)
+ : currRotX(0), currRotY(0),
+ speedx(speedx), speedy(speedy),
+ curvx(curvx), curvy(curvy){};
+
+ void tick(float adjust)
+ {
+ currRotX += speedx * adjust;
+ currRotY += speedy * adjust;
+ }
+
+ void transform(DemoItem *item, QPointF &pos)
+ {
+ DemoItem *parent = (DemoItem *) item->parentItem();
+ QPointF center = parent->boundingRect().center();
+ pos.setX(center.x() + (pos.x() - center.x()) * cos(currRotX + pos.x() * curvx));
+ pos.setY(center.y() + (pos.y() - center.y()) * cos(currRotY + pos.y() * curvy));
+ }
+};
+
+class PostRotateXYTwist : public TickerPostEffect
+{
+public:
+ float currRotX, currRotY;
+ float speedx, speedy, curvx, curvy;
+
+ PostRotateXYTwist(float speedx, float speedy, float curvx, float curvy)
+ : currRotX(0), currRotY(0),
+ speedx(speedx), speedy(speedy),
+ curvx(curvx), curvy(curvy){};
+
+ void tick(float adjust)
+ {
+ currRotX += speedx * adjust;
+ currRotY += speedy * adjust;
+ }
+
+ void transform(DemoItem *item, QPointF &pos)
+ {
+ DemoItem *parent = (DemoItem *) item->parentItem();
+ QPointF center = parent->boundingRect().center();
+ pos.setX(center.x() + (pos.x() - center.x()) * cos(currRotX + pos.y() * curvx));
+ pos.setY(center.y() + (pos.y() - center.y()) * cos(currRotY + pos.x() * curvy));
+ }
+};
+
+//////////////////// TICKER EFFECT STUFF //////////////////////////////////////
+
+class TickerEffect
+{
+ TickerPostEffect *postEffect;
+public:
+ enum EffectStatus{Normal, Intro, Outro} status;
+ LetterList *letters;
+ float morphSpeed, moveSpeed;
+ float normalMorphSpeed, normalMoveSpeed;
+ bool useSheepDog, morphBetweenModels;
+
+ TickerEffect(LetterList *letters)
+ : postEffect(new TickerPostEffect()), status(Intro), letters(letters),
+ morphSpeed(Colors::tickerMorphSpeed), moveSpeed(Colors::tickerMoveSpeed),
+ normalMorphSpeed(Colors::tickerMorphSpeed), normalMoveSpeed(Colors::tickerMoveSpeed),
+ useSheepDog(true), morphBetweenModels(!Colors::noTickerMorph){}
+
+ void setPostEffect(TickerPostEffect *effect)
+ {
+ delete postEffect;
+ postEffect = effect;
+ }
+
+ virtual ~TickerEffect()
+ {
+ delete postEffect;
+ }
+
+ void slowDownAfterIntro(float adjust)
+ {
+ if (morphBetweenModels){
+ if (status == Intro){
+ float dec = 0.1 * adjust;
+ moveSpeed -= dec;
+ if (moveSpeed < Colors::tickerMoveSpeed){
+ moveSpeed = normalMoveSpeed;
+ morphSpeed = normalMorphSpeed;
+ status = Normal;
+ }
+ }
+ }
+ }
+
+ void moveLetters(float adjust)
+ {
+ float adaptedMoveSpeed = this->moveSpeed * adjust;
+ float adaptedMorphSpeed = this->morphSpeed * adjust;
+ postEffect->tick(adjust);
+
+ for (int i=0; i<letters->size(); i++){
+ LetterItem *letter = letters->at(i);
+ letter->guideAdvance(this->morphBetweenModels ? adaptedMoveSpeed : Colors::tickerMoveSpeed);
+ letter->guideMove(this->morphBetweenModels ? adaptedMorphSpeed : -1);
+
+ QPointF pos = letter->getGuidedPos();
+ postEffect->transform(letter, pos);
+
+ if (useSheepDog)
+ letter->setPosUsingSheepDog(pos, QRectF(0, 0, 800, 600));
+ else
+ letter->setPos(pos);
+ }
+ }
+
+ virtual void tick(float adjust)
+ {
+ slowDownAfterIntro(adjust);
+ moveLetters(adjust);
+ }
+
+};
+
+class EffectWhirlWind : public TickerEffect
+{
+public:
+ EffectWhirlWind(LetterList *letters) : TickerEffect(letters)
+ {
+ moveSpeed = 50;
+ for (int i=0; i<this->letters->size(); i++){
+ LetterItem *letter = this->letters->at(i);
+ letter->setGuidedPos(QPointF(0, 100));
+ }
+ }
+};
+
+class EffectSnake : public TickerEffect
+{
+public:
+ EffectSnake(LetterList *letters) : TickerEffect(letters)
+ {
+ moveSpeed = 40;
+ for (int i=0; i<this->letters->size(); i++){
+ LetterItem *letter = this->letters->at(i);
+ letter->setGuidedPos(QPointF(0, -250 - (i * 5)));
+ }
+ }
+};
+
+class EffectScan : public TickerEffect
+{
+public:
+ EffectScan(LetterList *letters) : TickerEffect(letters)
+ {
+ for (int i=0; i<this->letters->size(); i++){
+ LetterItem *letter = this->letters->at(i);
+ letter->setGuidedPos(QPointF(100, -300));
+ }
+ }
+};
+
+class EffectRaindrops : public TickerEffect
+{
+public:
+ EffectRaindrops(LetterList *letters) : TickerEffect(letters)
+ {
+ for (int i=0; i<this->letters->size(); i++){
+ LetterItem *letter = this->letters->at(i);
+ letter->setGuidedPos(QPointF(-100 + rand() % 200, - 200.0f - rand() % 1300));
+ }
+ }
+};
+
+class EffectLine : public TickerEffect
+{
+public:
+ EffectLine(LetterList *letters) : TickerEffect(letters)
+ {
+ for (int i=0; i<this->letters->size(); i++){
+ LetterItem *letter = this->letters->at(i);
+ letter->setGuidedPos(QPointF(100, 500.0f + i * 20));
+ }
+ }
+};
+
+//////////////////// TICKER STUFF /////////////////////////////////////////////
+
+ItemCircleAnimation::ItemCircleAnimation(QGraphicsScene *scene, QGraphicsItem *parent)
+ : DemoItem(scene, parent)
+{
+ sscene = scene;
+ this->letterCount = Colors::tickerLetterCount;
+ this->scale = 1;
+ this->showCount = -1;
+ this->tickOnPaint = false;
+ this->paused = false;
+ this->doIntroTransitions = true;
+ this->setAcceptsHoverEvents(true);
+ this->setCursor(Qt::OpenHandCursor);
+ this->setupGuides();
+ this->setupLetters();
+ this->useGuideQt();
+ this->effect = 0;//new TickerEffect(this->letterList);
+}
+
+ItemCircleAnimation::~ItemCircleAnimation()
+{
+ delete this->letterList;
+ delete this->qtGuide1;
+ delete this->qtGuide2;
+ delete this->qtGuide3;
+ delete this->effect;
+}
+
+void ItemCircleAnimation::createLetter(char c)
+{
+ LetterItem *letter = new LetterItem(c, sscene, this);
+ this->letterList->append(letter);
+}
+
+void ItemCircleAnimation::setupLetters()
+{
+ this->letterList = new LetterList();
+
+ QString s = Colors::tickerText;
+ int len = s.length();
+ int i = 0;
+ for (; i < this->letterCount - len; i += len)
+ for (int l=0; l<len; l++)
+ createLetter(s[l].toLatin1());
+
+ // Fill inn with blanks:
+ for (; i < this->letterCount; ++i)
+ createLetter(' ');
+}
+
+void ItemCircleAnimation::setupGuides()
+{
+ int x = 0;
+ int y = 20;
+
+ this->qtGuide1 = new GuideCircle(QRectF(x, y, 260, 260), -36, 342);
+ new GuideLine(QPointF(x + 240, y + 268), this->qtGuide1);
+ new GuideLine(QPointF(x + 265, y + 246), this->qtGuide1);
+ new GuideLine(QPointF(x + 158, y + 134), this->qtGuide1);
+ new GuideLine(QPointF(x + 184, y + 109), this->qtGuide1);
+ new GuideLine(QPointF(x + 160, y + 82), this->qtGuide1);
+ new GuideLine(QPointF(x + 77, y + 163), this->qtGuide1); // T-top
+ new GuideLine(QPointF(x + 100, y + 190), this->qtGuide1);
+ new GuideLine(QPointF(x + 132, y + 159), this->qtGuide1);
+ new GuideLine(QPointF(x + 188, y + 211), this->qtGuide1);
+ new GuideCircle(QRectF(x + 30, y + 30, 200, 200), -30, 336, GuideCircle::CW, this->qtGuide1);
+ new GuideLine(QPointF(x + 238, y + 201), this->qtGuide1);
+
+ y = 30;
+ this->qtGuide2 = new GuideCircle(QRectF(x + 30, y + 30, 200, 200), 135, 270, GuideCircle::CCW);
+ new GuideLine(QPointF(x + 222, y + 38), this->qtGuide2);
+ new GuideCircle(QRectF(x, y, 260, 260), 135, 270, GuideCircle::CW, this->qtGuide2);
+ new GuideLine(QPointF(x + 59, y + 59), this->qtGuide2);
+
+ x = 115;
+ y = 10;
+ this->qtGuide3 = new GuideLine(QLineF(x, y, x + 30, y));
+ new GuideLine(QPointF(x + 30, y + 170), this->qtGuide3);
+ new GuideLine(QPointF(x, y + 170), this->qtGuide3);
+ new GuideLine(QPointF(x, y), this->qtGuide3);
+
+ this->qtGuide1->setFence(QRectF(0, 0, 800, 600));
+ this->qtGuide2->setFence(QRectF(0, 0, 800, 600));
+ this->qtGuide3->setFence(QRectF(0, 0, 800, 600));
+}
+
+void ItemCircleAnimation::useGuide(Guide *guide, int firstLetter, int lastLetter)
+{
+ float padding = guide->lengthAll() / float(lastLetter - firstLetter);
+ for (int i=firstLetter; i<lastLetter; i++){
+ LetterItem *letter = this->letterList->at(i);
+ letter->useGuide(guide, (i - firstLetter) * padding);
+ }
+}
+
+void ItemCircleAnimation::useGuideQt()
+{
+ if (this->currGuide != this->qtGuide1){
+ this->useGuide(qtGuide1, 0, this->letterCount);
+ this->currGuide = qtGuide1;
+ }
+}
+
+void ItemCircleAnimation::useGuideTt()
+{
+ if (this->currGuide != this->qtGuide2){
+ int split = int(this->letterCount * 5.0 / 7.0);
+ this->useGuide(qtGuide2, 0, split);
+ this->useGuide(qtGuide3, split, this->letterCount);
+ this->currGuide = qtGuide2;
+ }
+}
+
+QRectF ItemCircleAnimation::boundingRect() const
+{
+ return QRectF(0, 0, 300, 320);
+}
+
+void ItemCircleAnimation::prepare()
+{
+}
+
+void ItemCircleAnimation::switchToNextEffect()
+{
+ ++this->showCount;
+ delete this->effect;
+
+ switch (this->showCount){
+ case 1:
+ this->effect = new EffectSnake(this->letterList);
+ break;
+ case 2:
+ this->effect = new EffectLine(this->letterList);
+ this->effect->setPostEffect(new PostRotateXYTwist(0.01f, 0.0f, 0.003f, 0.0f));
+ break;
+ case 3:
+ this->effect = new EffectRaindrops(this->letterList);
+ this->effect->setPostEffect(new PostRotateXYTwist(0.01f, 0.005f, 0.003f, 0.003f));
+ break;
+ case 4:
+ this->effect = new EffectScan(this->letterList);
+ this->effect->normalMoveSpeed = 0;
+ this->effect->setPostEffect(new PostRotateXY(0.008f, 0.0f, 0.005f, 0.0f));
+ break;
+ default:
+ this->showCount = 0;
+ this->effect = new EffectWhirlWind(this->letterList);
+ }
+}
+
+void ItemCircleAnimation::animationStarted(int id)
+{
+ if (id == DemoItemAnimation::ANIM_IN){
+ if (this->doIntroTransitions){
+ // Make all letters dissapear
+ for (int i=0; i<this->letterList->size(); i++){
+ LetterItem *letter = this->letterList->at(i);
+ letter->setPos(1000, 0);
+ }
+ this->switchToNextEffect();
+ this->useGuideQt();
+ this->scale = 1;
+ // The first time we run, we have a rather large
+ // delay to perform benchmark before the ticker shows.
+ // But now, since we are showing, use a more appropriate value:
+ this->currentAnimation->startDelay = 1500;
+ }
+ }
+ else if (this->effect)
+ this->effect->useSheepDog = false;
+
+ this->tickTimer = QTime::currentTime();
+}
+
+void ItemCircleAnimation::animationStopped(int)
+{
+ // Nothing to do.
+}
+
+void ItemCircleAnimation::swapModel(){
+ if (this->currGuide == this->qtGuide2)
+ this->useGuideQt();
+ else
+ this->useGuideTt();
+}
+
+void ItemCircleAnimation::hoverEnterEvent(QGraphicsSceneHoverEvent *)
+{
+// Skip swap here to enhance ticker dragging
+// this->swapModel();
+}
+
+void ItemCircleAnimation::hoverLeaveEvent(QGraphicsSceneHoverEvent *)
+{
+ this->swapModel();
+}
+
+void ItemCircleAnimation::setTickerScale(float s)
+{
+ this->scale = s;
+ qtGuide1->setScale(this->scale, this->scale);
+ qtGuide2->setScale(this->scale, this->scale);
+ qtGuide3->setScale(this->scale, this->scale);
+}
+
+void ItemCircleAnimation::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ this->mouseMoveLastPosition = event->scenePos();
+ if (event->button() == Qt::LeftButton)
+ this->setCursor(Qt::ClosedHandCursor);
+ else
+ this->switchToNextEffect();
+}
+
+void ItemCircleAnimation::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton)
+ this->setCursor(Qt::OpenHandCursor);
+}
+
+void ItemCircleAnimation::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ QPointF newPosition = event->scenePos();
+ this->setPosUsingSheepDog(this->pos() + newPosition - this->mouseMoveLastPosition, QRectF(-260, -280, 1350, 1160));
+ this->mouseMoveLastPosition = newPosition;
+}
+
+void ItemCircleAnimation::wheelEvent(QGraphicsSceneWheelEvent *event)
+{
+ this->effect->moveSpeed = this->effect->moveSpeed + (event->delta() > 0 ? -0.20 : 0.20);
+ if (this->effect->moveSpeed < 0)
+ this->effect->moveSpeed = 0;
+}
+
+void ItemCircleAnimation::pause(bool on)
+{
+ this->paused = on;
+ this->tickTimer = QTime::currentTime();
+}
+
+void ItemCircleAnimation::tick()
+{
+ if (this->paused || !this->effect)
+ return;
+
+ float t = this->tickTimer.msecsTo(QTime::currentTime());
+ this->tickTimer = QTime::currentTime();
+ this->effect->tick(t/10.0f);
+}
+
+void ItemCircleAnimation::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
+{
+ if (this->tickOnPaint)
+ tick();
+}
+
+
+
+
diff --git a/demos/qtdemo/itemcircleanimation.h b/demos/qtdemo/itemcircleanimation.h
new file mode 100644
index 0000000..27e399c
--- /dev/null
+++ b/demos/qtdemo/itemcircleanimation.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ITEM_CIRCLE_ANIMATION_H
+#define ITEM_CIRCLE_ANIMATION_H
+
+#include <QtCore>
+#include <QObject>
+#include <QtGui>
+#include <QTimeLine>
+#include <QList>
+#include "demoitem.h"
+#include "letteritem.h"
+#include "guideline.h"
+#include "guidecircle.h"
+
+typedef QList<LetterItem *> LetterList;
+class TickerEffect;
+
+class ItemCircleAnimation : public QObject, public DemoItem
+{
+public:
+ ItemCircleAnimation(QGraphicsScene *scene = 0, QGraphicsItem *parent = 0);
+ virtual ~ItemCircleAnimation();
+
+ // overidden methods:
+ QRectF boundingRect() const;
+ void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
+ void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void wheelEvent(QGraphicsSceneWheelEvent *event);
+ void animationStarted(int id = 0);
+ void animationStopped(int id = 0);
+ void prepare();
+ void tick();
+ void switchToNextEffect();
+ void useGuideQt();
+ void useGuideTt();
+ void pause(bool on);
+
+ bool tickOnPaint;
+ bool paused;
+ bool doIntroTransitions;
+
+private:
+ void setupLetters();
+ void createLetter(char c);
+ void setupGuides();
+ void useGuide(Guide *guide, int firstLetter, int lastLetter);
+ void swapModel();
+ void setTickerScale(float s);
+
+ int showCount;
+ float scale;
+ QPointF mouseMoveLastPosition;
+ int letterCount;
+ LetterList *letterList;
+ Guide *qtGuide1;
+ Guide *qtGuide2;
+ Guide *qtGuide3;
+ Guide *currGuide;
+ TickerEffect *effect;
+ QTime tickTimer;
+};
+
+#endif // ITEM_CIRCLE_ANIMATION_H
+
+
+
diff --git a/demos/qtdemo/letteritem.cpp b/demos/qtdemo/letteritem.cpp
new file mode 100644
index 0000000..7b814b1
--- /dev/null
+++ b/demos/qtdemo/letteritem.cpp
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <cmath>
+#include "letteritem.h"
+#include "colors.h"
+
+LetterItem::LetterItem(char letter, QGraphicsScene *scene, QGraphicsItem *parent) : DemoItem(scene, parent), letter(letter)
+{
+ useSharedImage(QString(__FILE__) + letter);
+}
+
+LetterItem::~LetterItem()
+{
+}
+
+QImage *LetterItem::createImage(const QMatrix &matrix) const
+{
+ QRect scaledRect = matrix.mapRect(QRect(0, 0, 25, 25));
+ QImage *image = new QImage(scaledRect.width(), scaledRect.height(), QImage::Format_ARGB32_Premultiplied);
+ image->fill(0);
+ QPainter painter(image);
+ painter.scale(matrix.m11(), matrix.m22());
+ painter.setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ painter.setPen(Qt::NoPen);
+ if (Colors::useEightBitPalette){
+ painter.setBrush(QColor(102, 175, 54));
+ painter.drawEllipse(0, 0, 25, 25);
+ painter.setFont(Colors::tickerFont());
+ painter.setPen(QColor(255, 255, 255));
+ painter.drawText(10, 15, QString(this->letter));
+ }
+ else {
+ QLinearGradient brush(0, 0, 0, 25);
+ brush.setSpread(QLinearGradient::PadSpread);
+ brush.setColorAt(0.0, QColor(102, 175, 54, 200));
+ brush.setColorAt(1.0, QColor(102, 175, 54, 60));
+ painter.setBrush(brush);
+ painter.drawEllipse(0, 0, 25, 25);
+ painter.setFont(Colors::tickerFont());
+ painter.setPen(QColor(255, 255, 255, 255));
+ painter.drawText(10, 15, QString(this->letter));
+ }
+ return image;
+}
+
+
diff --git a/demos/qtdemo/letteritem.h b/demos/qtdemo/letteritem.h
new file mode 100644
index 0000000..8c3f16e
--- /dev/null
+++ b/demos/qtdemo/letteritem.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LETTER_ITEM_H
+#define LETTER_ITEM_H
+
+#include <QtGui>
+#include "demoitem.h"
+
+class LetterItem : public DemoItem
+{
+public:
+ LetterItem(char letter, QGraphicsScene *scene = 0, QGraphicsItem *parent = 0);
+ virtual ~LetterItem();
+
+protected:
+ QImage *createImage(const QMatrix &matrix) const;
+
+private:
+ char letter;
+};
+
+#endif // LETTER_ITEM_H
+
diff --git a/demos/qtdemo/main.cpp b/demos/qtdemo/main.cpp
new file mode 100644
index 0000000..bf2028d
--- /dev/null
+++ b/demos/qtdemo/main.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui>
+#include "mainwindow.h"
+#include "menumanager.h"
+#include "colors.h"
+
+static void artisticSleep(int sleepTime)
+{
+ QTime time;
+ time.restart();
+ while (time.elapsed() < sleepTime)
+ QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
+}
+
+int main(int argc, char *argv[])
+{
+ Q_INIT_RESOURCE(qtdemo);
+ QApplication app(argc, argv);
+ Colors::parseArgs(argc, argv);
+ MainWindow mainWindow;
+ MenuManager::instance()->init(&mainWindow);
+ mainWindow.setFocus();
+
+ if (Colors::fullscreen)
+ mainWindow.showFullScreen();
+ else {
+ mainWindow.enableMask(true);
+ mainWindow.show();
+ }
+
+ artisticSleep(500);
+ mainWindow.start();
+ return app.exec();
+}
diff --git a/demos/qtdemo/mainwindow.cpp b/demos/qtdemo/mainwindow.cpp
new file mode 100644
index 0000000..8723823
--- /dev/null
+++ b/demos/qtdemo/mainwindow.cpp
@@ -0,0 +1,483 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+#include "menumanager.h"
+#include "colors.h"
+#include "dockitem.h"
+#include "demotextitem.h"
+#include "imageitem.h"
+#include "demoitem.h"
+#include "demoscene.h"
+
+#ifndef QT_NO_OPENGL
+ #include <QGLWidget>
+#endif
+//#define QT_NO_OPENGL
+
+MainWindow::MainWindow(QWidget *parent) : QGraphicsView(parent), updateTimer(this)
+{
+ this->currentFps = Colors::fps;
+ this->loop = false;
+ this->fpsMedian = -1;
+ this->fpsLabel = 0;
+ this->pausedLabel = 0;
+ this->doneAdapt = false;
+ this->useTimer = false;
+ this->updateTimer.setSingleShot(true);
+ this->trolltechLogo = 0;
+ this->qtLogo = 0;
+ this->setupWidget();
+ this->setupScene();
+ this->setupSceneItems();
+ this->drawBackgroundToPixmap();
+}
+
+MainWindow::~MainWindow()
+{
+ delete this->trolltechLogo;
+ delete this->qtLogo;
+}
+
+void MainWindow::setupWidget()
+{
+ QRect screenRect = QApplication::desktop()->screenGeometry(QApplication::desktop()->primaryScreen());
+ QRect windowRect(0, 0, 800, 600);
+ if (screenRect.width() < 800)
+ windowRect.setWidth(screenRect.width());
+ if (screenRect.height() < 600)
+ windowRect.setHeight(screenRect.height());
+ windowRect.moveCenter(screenRect.center());
+ this->setGeometry(windowRect);
+ this->setMinimumSize(80, 60);
+ setWindowTitle(tr("Qt Examples and Demos"));
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setFrameStyle(QFrame::NoFrame);
+ this->setRenderingSystem();
+ connect(&this->updateTimer, SIGNAL(timeout()), this, SLOT(tick()));
+}
+
+void MainWindow::setRenderingSystem()
+{
+ QWidget *viewport = 0;
+
+ if (Colors::direct3dRendering){
+ viewport->setAttribute(Qt::WA_MSWindowsUseDirect3D);
+ setCacheMode(QGraphicsView::CacheNone);
+ if (Colors::verbose)
+ qDebug() << "- using Direct3D";
+ }
+#ifndef QT_NO_OPENGL
+ else if (Colors::openGlRendering){
+ QGLWidget *glw = new QGLWidget(QGLFormat(QGL::SampleBuffers));
+ if (Colors::noScreenSync)
+ glw->format().setSwapInterval(0);
+ glw->setAutoFillBackground(false);
+ viewport = glw;
+ setCacheMode(QGraphicsView::CacheNone);
+ if (Colors::verbose)
+ qDebug() << "- using OpenGL";
+ }
+#endif
+ else{ // software rendering
+ viewport = new QWidget;
+ setCacheMode(QGraphicsView::CacheBackground);
+ if (Colors::verbose)
+ qDebug() << "- using software rendering";
+ }
+
+ setViewport(viewport);
+}
+
+void MainWindow::start()
+{
+ this->switchTimerOnOff(true);
+ this->demoStartTime.restart();
+ MenuManager::instance()->itemSelected(MenuManager::ROOT, Colors::rootMenuName);
+ if (Colors::verbose)
+ qDebug("- starting demo");
+}
+
+void MainWindow::enableMask(bool enable)
+{
+ if (!enable || Colors::noWindowMask)
+ this->clearMask();
+ else {
+ QPolygon region;
+ region.setPoints(9,
+ // north side:
+ 0, 0,
+ 800, 0,
+ // east side:
+ // 800, 70,
+ // 790, 90,
+ // 790, 480,
+ // 800, 500,
+ 800, 600,
+ // south side:
+ 700, 600,
+ 670, 590,
+ 130, 590,
+ 100, 600,
+ 0, 600,
+ // west side:
+ // 0, 550,
+ // 10, 530,
+ // 10, 520,
+ // 0, 520,
+ 0, 0);
+ this->setMask(QRegion(region));
+ }
+}
+
+void MainWindow::setupScene()
+{
+ this->scene = new DemoScene(this);
+ this->scene->setSceneRect(0, 0, 800, 600);
+ setScene(this->scene);
+ this->scene->setItemIndexMethod(QGraphicsScene::NoIndex);
+}
+
+void MainWindow::drawItems(QPainter *painter, int numItems, QGraphicsItem **items, const QStyleOptionGraphicsItem* options)
+{
+ QGraphicsView::drawItems(painter, numItems, items, options);
+}
+
+void MainWindow::switchTimerOnOff(bool on)
+{
+ bool ticker = MenuManager::instance()->ticker && MenuManager::instance()->ticker->scene();
+ if (ticker)
+ MenuManager::instance()->ticker->tickOnPaint = !on || Colors::noTimerUpdate;
+
+ if (on && !Colors::noTimerUpdate){
+ this->useTimer = true;
+ this->setViewportUpdateMode(QGraphicsView::NoViewportUpdate);
+ this->fpsTime = QTime::currentTime();
+ this->updateTimer.start(int(1000 / Colors::fps));
+ }
+ else{
+ this->useTimer = false;
+ this->updateTimer.stop();
+ if (Colors::softwareRendering)
+ if (Colors::noTicker)
+ this->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
+ else
+ this->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
+ else
+ this->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
+ }
+}
+
+bool MainWindow::measureFps()
+{
+ // Calculate time diff:
+ float t = this->fpsTime.msecsTo(QTime::currentTime());
+ if (t == 0)
+ t = 0.01f;
+ this->currentFps = (1000.0f / t);
+ this->fpsHistory += this->currentFps;
+ this->fpsTime = QTime::currentTime();
+
+ // Calculate median:
+ int size = this->fpsHistory.size();
+ if (size == 10){
+ qSort(this->fpsHistory.begin(), this->fpsHistory.end());
+ this->fpsMedian = this->fpsHistory.at(int(size/2));
+ if (this->fpsMedian == 0)
+ this->fpsMedian = 0.01f;
+ this->fpsHistory.clear();
+ return true;
+ }
+ return false;
+}
+
+/**
+ Used for adaption in case things are so slow
+ that no median yet has been calculated
+*/
+void MainWindow::forceFpsMedianCalculation()
+{
+ if (this->fpsMedian != -1)
+ return;
+
+ int size = this->fpsHistory.size();
+ if (size == 0){
+ this->fpsMedian = 0.01f;
+ return;
+ }
+
+ qSort(this->fpsHistory.begin(), this->fpsHistory.end());
+ this->fpsMedian = this->fpsHistory.at(int(size/2));
+ if (this->fpsMedian == 0)
+ this->fpsMedian = 0.01f;
+}
+
+void MainWindow::tick()
+{
+ bool medianChanged = this->measureFps();
+ this->checkAdapt();
+
+ if (medianChanged && this->fpsLabel && Colors::showFps)
+ this->fpsLabel->setText(QString("FPS: ") + QString::number(int(this->currentFps)));
+
+ if (MenuManager::instance()->ticker)
+ MenuManager::instance()->ticker->tick();
+
+ this->viewport()->update();
+ if (Colors::softwareRendering)
+ QApplication::syncX();
+
+ if (this->useTimer)
+ this->updateTimer.start(int(1000 / Colors::fps));
+}
+
+void MainWindow::setupSceneItems()
+{
+ if (Colors::showFps){
+ this->fpsLabel = new DemoTextItem(QString("FPS: --"), Colors::buttonFont(), Qt::white, -1, this->scene, 0, DemoTextItem::DYNAMIC_TEXT);
+ this->fpsLabel->setZValue(100);
+ this->fpsLabel->setPos(Colors::stageStartX, 600 - QFontMetricsF(Colors::buttonFont()).height() - 5);
+ }
+
+ this->trolltechLogo = new ImageItem(QImage(":/images/trolltech-logo.png"), 1000, 1000, this->scene, 0, true, 0.5f);
+ this->qtLogo = new ImageItem(QImage(":/images/qtlogo_small.png"), 1000, 1000, this->scene, 0, true, 0.5f);
+ this->trolltechLogo->setZValue(100);
+ this->qtLogo->setZValue(100);
+ this->pausedLabel = new DemoTextItem(QString("PAUSED"), Colors::buttonFont(), Qt::white, -1, this->scene, 0);
+ this->pausedLabel->setZValue(100);
+ QFontMetricsF fm(Colors::buttonFont());
+ this->pausedLabel->setPos(Colors::stageWidth - fm.width("PAUSED"), 590 - fm.height());
+ this->pausedLabel->setRecursiveVisible(false);
+}
+
+void MainWindow::checkAdapt()
+{
+ if (this->doneAdapt
+ || Colors::noTimerUpdate
+ || this->demoStartTime.elapsed() < 2000)
+ return;
+
+ this->doneAdapt = true;
+ this->forceFpsMedianCalculation();
+ Colors::benchmarkFps = this->fpsMedian;
+ if (Colors::verbose)
+ qDebug() << "- benchmark:" << QString::number(Colors::benchmarkFps) << "FPS";
+
+ if (Colors::noAdapt)
+ return;
+
+ if (this->fpsMedian < 30){
+ if (MenuManager::instance()->ticker && MenuManager::instance()->ticker->scene()){
+ this->scene->removeItem(MenuManager::instance()->ticker);
+ Colors::noTimerUpdate = true;
+ this->switchTimerOnOff(false);
+ if (this->fpsLabel)
+ this->fpsLabel->setText(QString("FPS: (") + QString::number(this->fpsMedian) + QString(")"));
+ if (Colors::verbose)
+ qDebug() << "- benchmark adaption: removed ticker (fps < 30)";
+ }
+
+ if (this->fpsMedian < 20){
+ Colors::noAnimations = true;
+ if (Colors::verbose)
+ qDebug() << "- benchmark adaption: animations switched off (fps < 20)";
+ }
+
+ Colors::adapted = true;
+ }
+}
+
+int MainWindow::performBenchmark()
+{
+/*
+ QTime time;
+ time.restart();
+ while (time.elapsed() < 2000)
+ QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
+*/
+ return 0;
+}
+
+void MainWindow::drawBackgroundToPixmap()
+{
+ const QRectF r = this->scene->sceneRect();
+ this->background = QPixmap(qRound(r.width()), qRound(r.height()));
+ this->background.fill(Qt::black);
+ QPainter painter(&this->background);
+
+ if (false && Colors::useEightBitPalette){
+ painter.fillRect(r, Colors::sceneBg1);
+ } else {
+ QImage bg(":/images/demobg.png");
+ painter.drawImage(0, 0, bg);
+ }
+}
+
+void MainWindow::drawBackground(QPainter *painter, const QRectF &rect)
+{
+ Q_UNUSED(rect);
+ painter->drawPixmap(QPoint(0, 0), this->background);
+}
+
+void MainWindow::showEvent(QShowEvent * event)
+{
+ Q_UNUSED(event);
+ QGraphicsView::showEvent(event);
+}
+
+void MainWindow::toggleFullscreen()
+{
+ if (this->isFullScreen()){
+ this->enableMask(true);
+ this->showNormal();
+ if (MenuManager::instance()->ticker)
+ MenuManager::instance()->ticker->pause(false);
+ }
+ else {
+ this->enableMask(false);
+ this->showFullScreen();
+ }
+}
+
+void MainWindow::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_Escape){
+ this->loop = false;
+ QApplication::quit();
+ }
+ else if (event->key() == Qt::Key_1){
+ QString s("");
+ s += "Rendering system: ";
+ if (Colors::openGlRendering)
+ s += "OpenGL";
+ else if (Colors::direct3dRendering)
+ s += "Direct3D";
+ else
+ s += "software";
+
+ s += "\nAdapt: ";
+ s += Colors::noAdapt ? "off" : "on";
+ s += "\nAdaption occured: ";
+ s += Colors::adapted ? "yes" : "no";
+ s += "\nOpenGL version: ";
+ s += Colors::glVersion;
+ QWidget w;
+ s += "\nColor bit depth: ";
+ s += QString::number(w.depth());
+ s += "\nWanted FPS: ";
+ s += QString::number(Colors::fps);
+ s += "\nBenchmarked FPS: ";
+ s += Colors::benchmarkFps != -1 ? QString::number(Colors::benchmarkFps) : "not calculated";
+ s += "\nAnimations: ";
+ s += Colors::noAnimations ? "off" : "on";
+ s += "\nBlending: ";
+ s += Colors::useEightBitPalette ? "off" : "on";
+ s += "\nTicker: ";
+ s += Colors::noTicker ? "off" : "on";
+ s += "\nPixmaps: ";
+ s += Colors::usePixmaps ? "on" : "off";
+ s += "\nRescale images on resize: ";
+ s += Colors::noRescale ? "off" : "on";
+ s += "\nTimer based updates: ";
+ s += Colors::noTimerUpdate ? "off" : "on";
+ s += "\nSeparate loop: ";
+ s += Colors::useLoop ? "yes" : "no";
+ s += "\nScreen sync: ";
+ s += Colors::noScreenSync ? "no" : "yes";
+ QMessageBox::information(0, QString("Current configuration"), s);
+ }
+}
+
+void MainWindow::focusInEvent(QFocusEvent *)
+{
+ if (!Colors::pause)
+ return;
+
+ if (MenuManager::instance()->ticker)
+ MenuManager::instance()->ticker->pause(false);
+
+ int code = MenuManager::instance()->currentMenuCode;
+ if (code == MenuManager::ROOT || code == MenuManager::MENU1)
+ this->switchTimerOnOff(true);
+
+ this->pausedLabel->setRecursiveVisible(false);
+}
+
+void MainWindow::focusOutEvent(QFocusEvent *)
+{
+ if (!Colors::pause)
+ return;
+
+ if (MenuManager::instance()->ticker)
+ MenuManager::instance()->ticker->pause(true);
+
+ int code = MenuManager::instance()->currentMenuCode;
+ if (code == MenuManager::ROOT || code == MenuManager::MENU1)
+ this->switchTimerOnOff(false);
+
+ this->pausedLabel->setRecursiveVisible(true);
+}
+
+void MainWindow::resizeEvent(QResizeEvent *event)
+{
+ Q_UNUSED(event);
+
+ this->resetMatrix();
+ this->scale(event->size().width() / 800.0, event->size().height() / 600.0);
+ QGraphicsView::resizeEvent(event);
+ DemoItem::setMatrix(this->matrix());
+
+ if (this->trolltechLogo){
+ const QRectF r = this->scene->sceneRect();
+ QRectF ttb = this->trolltechLogo->boundingRect();
+ this->trolltechLogo->setPos(int((r.width() - ttb.width()) / 2), 595 - ttb.height());
+ QRectF qtb = this->qtLogo->boundingRect();
+ this->qtLogo->setPos(802 - qtb.width(), 0);
+ }
+
+ // Changing size will almost always
+ // hurt FPS during the changing. So
+ // ignore it.
+ this->fpsHistory.clear();
+}
+
+
diff --git a/demos/qtdemo/mainwindow.h b/demos/qtdemo/mainwindow.h
new file mode 100644
index 0000000..388a392
--- /dev/null
+++ b/demos/qtdemo/mainwindow.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAIN_WINDOW_H
+#define MAIN_WINDOW_H
+
+#include <QtGui>
+#include <QPixmap>
+
+class DemoTextItem;
+class ImageItem;
+
+class MainWindow : public QGraphicsView
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+ void enableMask(bool enable);
+ void toggleFullscreen();
+ int performBenchmark();
+ void switchTimerOnOff(bool on);
+ void start();
+
+ QGraphicsScene *scene;
+ bool loop;
+
+ // FPS stuff:
+ QList<QTime> frameTimeList;
+ QList<float> fpsHistory;
+ float currentFps;
+ float fpsMedian;
+ DemoTextItem *fpsLabel;
+
+protected:
+ // Overidden methods:
+ void showEvent(QShowEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void resizeEvent(QResizeEvent *event);
+ void drawBackground(QPainter *painter, const QRectF &rect);
+ void drawItems(QPainter *painter, int numItems, QGraphicsItem ** items, const QStyleOptionGraphicsItem* options);
+ void focusInEvent(QFocusEvent *event);
+ void focusOutEvent(QFocusEvent *event);
+
+private slots:
+ void tick();
+
+private:
+ void setupWidget();
+ void setupSceneItems();
+ void drawBackgroundToPixmap();
+ void setupScene();
+ bool measureFps();
+ void forceFpsMedianCalculation();
+ void checkAdapt();
+ void setRenderingSystem();
+
+ QTimer updateTimer;
+ QTime demoStartTime;
+ QTime fpsTime;
+ QPixmap background;
+ ImageItem *trolltechLogo;
+ ImageItem *qtLogo;
+ bool doneAdapt;
+ bool useTimer;
+ DemoTextItem *pausedLabel;
+};
+
+#endif // MAIN_WINDOW_H
+
diff --git a/demos/qtdemo/menucontent.cpp b/demos/qtdemo/menucontent.cpp
new file mode 100644
index 0000000..a74cfe4
--- /dev/null
+++ b/demos/qtdemo/menucontent.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "menucontent.h"
+#include "colors.h"
+#include "menumanager.h"
+#include "demotextitem.h"
+#include "headingitem.h"
+
+MenuContentItem::MenuContentItem(const QDomElement &el, QGraphicsScene *scene, QGraphicsItem *parent)
+ : DemoItem(scene, parent)
+{
+ this->name = el.attribute("name");
+ this->heading = 0;
+ this->description1 = 0;
+ this->description2 = 0;
+
+ if (el.tagName() == "demos")
+ this->readmePath = QLibraryInfo::location(QLibraryInfo::DemosPath) + "/README";
+ else
+ this->readmePath = QLibraryInfo::location(QLibraryInfo::ExamplesPath) + "/" + el.attribute("dirname") + "/README";
+
+}
+
+void MenuContentItem::prepare()
+{
+ if (!this->prepared){
+ this->prepared= true;
+ this->createContent();
+ }
+}
+
+void MenuContentItem::animationStopped(int id)
+{
+ if (this->name == Colors::rootMenuName)
+ return; // Optimization hack.
+
+ if (id == DemoItemAnimation::ANIM_OUT){
+ // Free up some memory:
+ delete this->heading;
+ delete this->description1;
+ delete this->description2;
+ this->heading = 0;
+ this->description1 = 0;
+ this->description2 = 0;
+ this->prepared = false;
+ }
+}
+
+QString MenuContentItem::loadDescription(int startPara, int nrPara)
+{
+ QString result;
+ QFile readme(this->readmePath);
+ if (!readme.open(QFile::ReadOnly)){
+ if (Colors::verbose)
+ qDebug() << "- MenuContentItem::loadDescription: Could not load:" << this->readmePath;
+ return "";
+ }
+
+ QTextStream in(&readme);
+ // Skip a certain number of paragraphs:
+ while (startPara)
+ if (in.readLine().isEmpty()) --startPara;
+
+ // Read in the number of wanted paragraphs:
+ QString line = in.readLine();
+ do {
+ result += line + " ";
+ line = in.readLine();
+ if (line.isEmpty()){
+ --nrPara;
+ line = "<br><br>" + in.readLine();
+ }
+ } while (nrPara && !in.atEnd());
+
+ return Colors::contentColor + result;
+}
+
+void MenuContentItem::createContent()
+{
+ // Create the items:
+ this->heading = new HeadingItem(this->name, this->scene(), this);
+ QString para1 = this->loadDescription(0, 1);
+ if (para1.isEmpty())
+ para1 = Colors::contentColor + QLatin1String("Could not load description. Ensure that the documentation for Qt is built.");
+ QColor bgcolor = Colors::sceneBg1.darker(200);
+ bgcolor.setAlpha(100);
+ this->description1 = new DemoTextItem(para1, Colors::contentFont(), Colors::heading, 500, this->scene(), this, DemoTextItem::STATIC_TEXT);
+ this->description2 = new DemoTextItem(this->loadDescription(1, 2), Colors::contentFont(), Colors::heading, 250, this->scene(), this, DemoTextItem::STATIC_TEXT);
+
+ // Place the items on screen:
+ this->heading->setPos(0, 3);
+ this->description1->setPos(0, this->heading->pos().y() + this->heading->boundingRect().height() + 10);
+ this->description2->setPos(0, this->description1->pos().y() + this->description1->boundingRect().height() + 15);
+}
+
+QRectF MenuContentItem::boundingRect() const
+{
+ return QRectF(0, 0, 500, 350);
+}
+
+
diff --git a/demos/qtdemo/menucontent.h b/demos/qtdemo/menucontent.h
new file mode 100644
index 0000000..737492d
--- /dev/null
+++ b/demos/qtdemo/menucontent.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MENU_CONTENT_ITEM_H
+#define MENU_CONTENT_ITEM_H
+
+#include <QtGui>
+#include <QtXml>
+#include "demoitem.h"
+
+class HeadingItem;
+class DemoTextItem;
+
+class MenuContentItem : public DemoItem
+{
+
+public:
+ MenuContentItem(const QDomElement &el, QGraphicsScene *scene = 0, QGraphicsItem *parent = 0);
+
+ virtual QRectF boundingRect() const; // overridden
+ virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0){}; // overridden
+ void animationStopped(int id);
+ void prepare();
+
+private:
+ QString name;
+ QString readmePath;
+ HeadingItem *heading;
+ DemoTextItem *description1;
+ DemoTextItem *description2;
+
+ QString loadDescription(int startPara, int nrPara);
+ QString extractTextFromParagraph(const QDomNode &parentNode);
+
+ void createContent();
+};
+
+#endif // MENU_CONTENT_ITEM_H
+
diff --git a/demos/qtdemo/menumanager.cpp b/demos/qtdemo/menumanager.cpp
new file mode 100644
index 0000000..bfa2e3f
--- /dev/null
+++ b/demos/qtdemo/menumanager.cpp
@@ -0,0 +1,876 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "menumanager.h"
+#include "colors.h"
+#include "menucontent.h"
+#include "examplecontent.h"
+
+MenuManager *MenuManager::pInstance = 0;
+
+MenuManager * MenuManager::instance()
+{
+ if (!MenuManager::pInstance)
+ MenuManager::pInstance = new MenuManager();
+ return MenuManager::pInstance;
+}
+
+MenuManager::MenuManager()
+{
+ this->ticker = 0;
+ this->tickerInAnim = 0;
+ this->upButton = 0;
+ this->downButton = 0;
+ this->helpEngine = 0;
+ this->score = new Score();
+ this->currentMenu = QLatin1String("[no menu visible]");
+ this->currentCategory = QLatin1String("[no category visible]");
+ this->currentMenuButtons = QLatin1String("[no menu buttons visible]");
+ this->currentInfo = QLatin1String("[no info visible]");
+ this->currentMenuCode = -1;
+ this->readXmlDocument();
+ this->initHelpEngine();
+}
+
+MenuManager::~MenuManager()
+{
+ delete this->score;
+ delete this->contentsDoc;
+ delete this->helpEngine;
+}
+
+QByteArray MenuManager::getResource(const QString &name)
+{
+ QByteArray ba = this->helpEngine->fileData(name);
+ if (Colors::verbose && ba.isEmpty())
+ qDebug() << " - WARNING: Could not get " << name;
+ return ba;
+}
+
+void MenuManager::readXmlDocument()
+{
+ this->contentsDoc = new QDomDocument();
+ QString errorStr;
+ int errorLine;
+ int errorColumn;
+
+ QFile file(":/xml/examples.xml");
+ bool statusOK = this->contentsDoc->setContent(&file, true, &errorStr, &errorLine, &errorColumn);
+ if (!statusOK){
+ QMessageBox::critical(0,
+ QObject::tr("DOM Parser"),
+ QObject::tr("Could not read or find the contents document. Error at line %1, column %2:\n%3")
+ .arg(errorLine).arg(errorColumn).arg(errorStr)
+ );
+ exit(-1);
+ }
+}
+
+void MenuManager::initHelpEngine()
+{
+ this->helpRootUrl = QString("qthelp://com.trolltech.qt.%1%2%3/qdoc/")
+ .arg(QT_VERSION >> 16).arg((QT_VERSION >> 8) & 0xFF)
+ .arg(QT_VERSION & 0xFF);
+
+ // Store help collection file in cache dir of assistant
+ QString cacheDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation)
+ + QLatin1String("/Trolltech/Assistant/");
+ QString helpDataFile = QString(QLatin1String("qtdemo_%1.qhc")).arg(QLatin1String(QT_VERSION_STR));
+
+ QDir dir;
+ if (!dir.exists(cacheDir))
+ dir.mkpath(cacheDir);
+
+ // Create help engine (and new
+ // helpDataFile if it does not exist):
+ this->helpEngine = new QHelpEngineCore(cacheDir + helpDataFile);
+ this->helpEngine->setupData();
+
+ QString qtDocRoot = QLibraryInfo::location(QLibraryInfo::DocumentationPath) + QLatin1String("/qch");
+ qtDocRoot = QDir(qtDocRoot).absolutePath();
+
+ QStringList qchFiles;
+ qchFiles << QLatin1String("/qt.qch")
+ << QLatin1String("/designer.qch")
+ << QLatin1String("/linguist.qch");
+
+ QString oldDir = helpEngine->customValue(QLatin1String("docDir"), QString()).toString();
+ if (oldDir != qtDocRoot) {
+ foreach (const QString &qchFile, qchFiles)
+ helpEngine->unregisterDocumentation(QHelpEngineCore::namespaceName(qtDocRoot + qchFile));
+ }
+
+ // If the data that the engine will work
+ // on is not yet registered, do it now:
+ foreach (const QString &qchFile, qchFiles)
+ helpEngine->registerDocumentation(qtDocRoot + qchFile);
+
+ helpEngine->setCustomValue(QLatin1String("docDir"), qtDocRoot);
+}
+
+void MenuManager::itemSelected(int userCode, const QString &menuName)
+{
+ switch (userCode){
+ case LAUNCH:
+ this->launchExample(this->currentInfo);
+ break;
+ case DOCUMENTATION:
+ this->showDocInAssistant(this->currentInfo);
+ break;
+ case QUIT:
+ this->window->loop = false;
+ QCoreApplication::quit();
+ break;
+ case FULLSCREEN:
+ this->window->toggleFullscreen();
+ break;
+ case ROOT:
+ // out:
+ this->score->queueMovie(this->currentMenu + " -out", Score::FROM_START, Score::LOCK_ITEMS);
+ this->score->queueMovie(this->currentMenuButtons + " -out", Score::FROM_START, Score::LOCK_ITEMS);
+ this->score->queueMovie(this->currentInfo + " -out");
+ this->score->queueMovie(this->currentInfo + " -buttons -out", Score::NEW_ANIMATION_ONLY);
+ this->score->queueMovie("back -out", Score::ONLY_IF_VISIBLE);
+ // book-keeping:
+ this->currentMenuCode = ROOT;
+ this->currentMenu = menuName + " -menu1";
+ this->currentMenuButtons = menuName + " -buttons";
+ this->currentInfo = menuName + " -info";
+ // in:
+ this->score->queueMovie("upndown -shake");
+ this->score->queueMovie(this->currentMenu, Score::FROM_START, Score::UNLOCK_ITEMS);
+ this->score->queueMovie(this->currentMenuButtons, Score::FROM_START, Score::UNLOCK_ITEMS);
+ this->score->queueMovie(this->currentInfo);
+ if (!Colors::noTicker){
+ this->ticker->doIntroTransitions = true;
+ this->tickerInAnim->startDelay = 2000;
+ this->ticker->useGuideQt();
+ this->score->queueMovie("ticker", Score::NEW_ANIMATION_ONLY);
+ this->window->switchTimerOnOff(true);
+ }
+ break;
+ case MENU1:
+ // out:
+ this->score->queueMovie(this->currentMenu + " -out", Score::FROM_START, Score::LOCK_ITEMS);
+ this->score->queueMovie(this->currentMenuButtons + " -out", Score::FROM_START, Score::LOCK_ITEMS);
+ this->score->queueMovie(this->currentInfo + " -out");
+ // book-keeping:
+ this->currentMenuCode = MENU1;
+ this->currentCategory = menuName;
+ this->currentMenu = menuName + " -menu1";
+ this->currentInfo = menuName + " -info";
+ // in:
+ this->score->queueMovie("upndown -shake");
+ this->score->queueMovie("back -in");
+ this->score->queueMovie(this->currentMenu, Score::FROM_START, Score::UNLOCK_ITEMS);
+ this->score->queueMovie(this->currentInfo);
+ if (!Colors::noTicker)
+ this->ticker->useGuideTt();
+ break;
+ case MENU2:
+ // out:
+ this->score->queueMovie(this->currentInfo + " -out", Score::NEW_ANIMATION_ONLY);
+ this->score->queueMovie(this->currentInfo + " -buttons -out", Score::NEW_ANIMATION_ONLY);
+ // book-keeping:
+ this->currentMenuCode = MENU2;
+ this->currentInfo = menuName;
+ // in / shake:
+ this->score->queueMovie("upndown -shake");
+ this->score->queueMovie("back -shake");
+ this->score->queueMovie(this->currentMenu + " -shake");
+ this->score->queueMovie(this->currentInfo, Score::NEW_ANIMATION_ONLY);
+ this->score->queueMovie(this->currentInfo + " -buttons", Score::NEW_ANIMATION_ONLY);
+ if (!Colors::noTicker){
+ this->score->queueMovie("ticker -out", Score::NEW_ANIMATION_ONLY);
+ this->window->switchTimerOnOff(false);
+ }
+ break;
+ case UP:{
+ QString backMenu = this->info[this->currentMenu]["back"];
+ if (!backMenu.isNull()){
+ this->score->queueMovie(this->currentMenu + " -top_out", Score::FROM_START, Score::LOCK_ITEMS);
+ this->score->queueMovie(backMenu + " -bottom_in", Score::FROM_START, Score::UNLOCK_ITEMS);
+ this->currentMenu = backMenu;
+ }
+ break; }
+ case DOWN:{
+ QString moreMenu = this->info[this->currentMenu]["more"];
+ if (!moreMenu.isNull()){
+ this->score->queueMovie(this->currentMenu + " -bottom_out", Score::FROM_START, Score::LOCK_ITEMS);
+ this->score->queueMovie(moreMenu + " -top_in", Score::FROM_START, Score::UNLOCK_ITEMS);
+ this->currentMenu = moreMenu;
+ }
+ break; }
+ case BACK:{
+ if (this->currentMenuCode == MENU2){
+ // out:
+ this->score->queueMovie(this->currentInfo + " -out", Score::NEW_ANIMATION_ONLY);
+ this->score->queueMovie(this->currentInfo + " -buttons -out", Score::NEW_ANIMATION_ONLY);
+ // book-keeping:
+ this->currentMenuCode = MENU1;
+ this->currentMenuButtons = this->currentCategory + " -buttons";
+ this->currentInfo = this->currentCategory + " -info";
+ // in / shake:
+ this->score->queueMovie("upndown -shake");
+ this->score->queueMovie(this->currentMenu + " -shake");
+ this->score->queueMovie(this->currentInfo, Score::NEW_ANIMATION_ONLY);
+ this->score->queueMovie(this->currentInfo + " -buttons", Score::NEW_ANIMATION_ONLY);
+ if (!Colors::noTicker){
+ this->ticker->doIntroTransitions = false;
+ this->tickerInAnim->startDelay = 500;
+ this->score->queueMovie("ticker", Score::NEW_ANIMATION_ONLY);
+ this->window->switchTimerOnOff(true);
+ }
+ } else if (this->currentMenuCode != ROOT)
+ itemSelected(ROOT, Colors::rootMenuName);
+ break; }
+ }
+
+ // update back- and more buttons
+ bool noBackMenu = this->info[this->currentMenu]["back"].isNull();
+ bool noMoreMenu = this->info[this->currentMenu]["more"].isNull();
+ this->upButton->setState(noBackMenu ? TextButton::DISABLED : TextButton::OFF);
+ this->downButton->setState(noMoreMenu ? TextButton::DISABLED : TextButton::OFF);
+
+ if (this->score->hasQueuedMovies()){
+ this->score->playQue();
+ // Playing new movies might include
+ // loading etc. So ignore the FPS
+ // at this point
+ this->window->fpsHistory.clear();
+ }
+}
+
+void MenuManager::showDocInAssistant(const QString &name)
+{
+ QString url = this->resolveDocUrl(name);
+ if (Colors::verbose)
+ qDebug() << "Sending URL to Assistant:" << url;
+
+ // Start assistant if it's not already running:
+ if (this->assistantProcess.state() != QProcess::Running){
+ QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator();
+#if !defined(Q_OS_MAC)
+ app += QLatin1String("assistant");
+#else
+ app += QLatin1String("Assistant.app/Contents/MacOS/Assistant");
+#endif
+ QStringList args;
+ args << QLatin1String("-enableRemoteControl");
+ this->assistantProcess.start(app, args);
+ if (!this->assistantProcess.waitForStarted()) {
+ QMessageBox::critical(0, tr("Qt Demo"), tr("Could not start Qt Assistant.").arg(app));
+ return;
+ }
+ }
+
+ // Send command through remote control even if the process
+ // was started to activate assistant and bring it to front:
+ QTextStream str(&this->assistantProcess);
+ str << "SetSource " << url << QLatin1Char('\0') << endl;
+}
+
+void MenuManager::launchExample(const QString &name)
+{
+ QString executable = this->resolveExeFile(name);
+#ifdef Q_OS_MAC
+ if (Colors::verbose)
+ qDebug() << "Launching:" << executable;
+ bool success = QDesktopServices::openUrl(QUrl::fromLocalFile(executable));
+ if (!success){
+ QMessageBox::critical(0, tr("Failed to launch the example"),
+ tr("Could not launch the example. Ensure that it has been built."),
+ QMessageBox::Cancel);
+ }
+#else // Not mac. To not break anything regarding dll's etc, keep it the way it was before:
+ QProcess *process = new QProcess(this);
+ connect(process, SIGNAL(finished(int)), this, SLOT(exampleFinished()));
+ connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(exampleError(QProcess::ProcessError)));
+
+#ifdef Q_OS_WIN
+ //make sure it finds the dlls on windows
+ QString curpath = QString::fromLocal8Bit(qgetenv("PATH").constData());
+ QString newpath = QString("PATH=%1;%2").arg(QLibraryInfo::location(QLibraryInfo::BinariesPath), curpath);
+ process->setEnvironment(QStringList(newpath));
+#endif
+
+ if (info[name]["changedirectory"] != "false"){
+ QString workingDirectory = resolveDataDir(name);
+ process->setWorkingDirectory(workingDirectory);
+ if (Colors::verbose)
+ qDebug() << "Setting working directory:" << workingDirectory;
+ }
+
+ if (Colors::verbose)
+ qDebug() << "Launching:" << executable;
+ process->start(executable);
+#endif
+}
+
+void MenuManager::exampleFinished()
+{
+}
+
+void MenuManager::exampleError(QProcess::ProcessError error)
+{
+ if (error != QProcess::Crashed)
+ QMessageBox::critical(0, tr("Failed to launch the example"),
+ tr("Could not launch the example. Ensure that it has been built."),
+ QMessageBox::Cancel);
+}
+
+void MenuManager::init(MainWindow *window)
+{
+ this->window = window;
+
+ // Create div:
+ this->createTicker();
+ this->createUpnDownButtons();
+ this->createBackButton();
+
+ // Create first level menu:
+ QDomElement rootElement = this->contentsDoc->documentElement();
+ this->createRootMenu(rootElement);
+
+ // Create second level menus:
+ QDomNode level2MenuNode = rootElement.firstChild();
+ while (!level2MenuNode.isNull()){
+ QDomElement level2MenuElement = level2MenuNode.toElement();
+ this->createSubMenu(level2MenuElement);
+
+ // create leaf menu and example info:
+ QDomNode exampleNode = level2MenuElement.firstChild();
+ while (!exampleNode.isNull()){
+ QDomElement exampleElement = exampleNode.toElement();
+ this->readInfoAboutExample(exampleElement);
+ this->createLeafMenu(exampleElement);
+ exampleNode = exampleNode.nextSibling();
+ }
+
+ level2MenuNode = level2MenuNode.nextSibling();
+ }
+}
+
+void MenuManager::readInfoAboutExample(const QDomElement &example)
+{
+ QString name = example.attribute("name");
+ if (this->info.contains(name))
+ qWarning() << "__WARNING: MenuManager::readInfoAboutExample: Demo/example with name"
+ << name << "appears twize in the xml-file!__";
+
+ this->info[name]["filename"] = example.attribute("filename");
+ this->info[name]["category"] = example.parentNode().toElement().tagName();
+ this->info[name]["dirname"] = example.parentNode().toElement().attribute("dirname");
+ this->info[name]["changedirectory"] = example.attribute("changedirectory");
+ this->info[name]["image"] = example.attribute("image");
+}
+
+QString MenuManager::resolveDataDir(const QString &name)
+{
+ QString dirName = this->info[name]["dirname"];
+ QString category = this->info[name]["category"];
+ QString fileName = this->info[name]["filename"];
+
+ QDir dir;
+ if (category == "demos")
+ dir = QDir(QLibraryInfo::location(QLibraryInfo::DemosPath));
+ else
+ dir = QDir(QLibraryInfo::location(QLibraryInfo::ExamplesPath));
+
+ dir.cd(dirName);
+ dir.cd(fileName);
+ return dir.absolutePath();
+}
+
+QString MenuManager::resolveExeFile(const QString &name)
+{
+ QString dirName = this->info[name]["dirname"];
+ QString category = this->info[name]["category"];
+ QString fileName = this->info[name]["filename"];
+
+ QDir dir;
+ if (category == "demos")
+ dir = QDir(QLibraryInfo::location(QLibraryInfo::DemosPath));
+ else
+ dir = QDir(QLibraryInfo::location(QLibraryInfo::ExamplesPath));
+
+ dir.cd(dirName);
+ dir.cd(fileName);
+
+ QFile unixFile(dir.path() + "/" + fileName);
+ if (unixFile.exists()) return unixFile.fileName();
+ QFile winR(dir.path() + "\\release\\" + fileName + ".exe");
+ if (winR.exists()) return winR.fileName();
+ QFile winD(dir.path() + "\\debug\\" + fileName + ".exe");
+ if (winD.exists()) return winD.fileName();
+ QFile mac(dir.path() + "/" + fileName + ".app");
+ if (mac.exists()) return mac.fileName();
+
+ if (Colors::verbose)
+ qDebug() << "- WARNING: Could not resolve executable:" << dir.path() << fileName;
+ return "__executable not found__";
+}
+
+QString MenuManager::resolveDocUrl(const QString &name)
+{
+ QString dirName = this->info[name]["dirname"];
+ QString category = this->info[name]["category"];
+ QString fileName = this->info[name]["filename"];
+
+ if (category == "demos")
+ return this->helpRootUrl + "demos-" + fileName + ".html";
+ else
+ return this->helpRootUrl + dirName.replace("/", "-") + "-" + fileName + ".html";
+}
+
+QString MenuManager::resolveImageUrl(const QString &name)
+{
+ return this->helpRootUrl + "images/" + name;
+}
+
+QByteArray MenuManager::getHtml(const QString &name)
+{
+ return getResource(this->resolveDocUrl(name));
+}
+
+QByteArray MenuManager::getImage(const QString &name)
+{
+ QString imageName = this->info[name]["image"];
+ QString category = this->info[name]["category"];
+ QString fileName = this->info[name]["filename"];
+
+ if (imageName.isEmpty()){
+ if (category == "demos")
+ imageName = fileName + "-demo.png";
+ else
+ imageName = fileName + "-example.png";
+ if ((getResource(resolveImageUrl(imageName))).isEmpty())
+ imageName = fileName + ".png";
+ if ((getResource(resolveImageUrl(imageName))).isEmpty())
+ imageName = fileName + "example.png";
+ }
+ return getResource(resolveImageUrl(imageName));
+}
+
+
+void MenuManager::createRootMenu(const QDomElement &el)
+{
+ QString name = el.attribute("name");
+ createMenu(el, MENU1);
+ createInfo(new MenuContentItem(el, this->window->scene, 0), name + " -info");
+
+ Movie *menuButtonsIn = this->score->insertMovie(name + " -buttons");
+ Movie *menuButtonsOut = this->score->insertMovie(name + " -buttons -out");
+ createLowLeftButton(QLatin1String("Quit"), QUIT, menuButtonsIn, menuButtonsOut, 0);
+ createLowRightButton("Toggle fullscreen", FULLSCREEN, menuButtonsIn, menuButtonsOut, 0);
+}
+
+void MenuManager::createSubMenu(const QDomElement &el)
+{
+ QString name = el.attribute("name");
+ createMenu(el, MENU2);
+ createInfo(new MenuContentItem(el, this->window->scene, 0), name + " -info");
+}
+
+void MenuManager::createLeafMenu(const QDomElement &el)
+{
+ QString name = el.attribute("name");
+ createInfo(new ExampleContent(name, this->window->scene, 0), name);
+
+ Movie *infoButtonsIn = this->score->insertMovie(name + " -buttons");
+ Movie *infoButtonsOut = this->score->insertMovie(name + " -buttons -out");
+ createLowRightLeafButton("Documentation", 600, DOCUMENTATION, infoButtonsIn, infoButtonsOut, 0);
+ if (el.attribute("executable") != "false")
+ createLowRightLeafButton("Launch", 405, LAUNCH, infoButtonsIn, infoButtonsOut, 0);
+}
+
+void MenuManager::createMenu(const QDomElement &category, BUTTON_TYPE type)
+{
+ qreal sw = this->window->scene->sceneRect().width();
+ int xOffset = 15;
+ int yOffset = 10;
+ int maxExamples = Colors::menuCount;
+ int menuIndex = 1;
+ QString name = category.attribute("name");
+ QDomNode currentNode = category.firstChild();
+ QString currentMenu = name + QLatin1String(" -menu") + QString::number(menuIndex);
+
+ while (!currentNode.isNull()){
+ Movie *movieIn = this->score->insertMovie(currentMenu);
+ Movie *movieOut = this->score->insertMovie(currentMenu + " -out");
+ Movie *movieNextTopOut = this->score->insertMovie(currentMenu + " -top_out");
+ Movie *movieNextBottomOut = this->score->insertMovie(currentMenu + " -bottom_out");
+ Movie *movieNextTopIn = this->score->insertMovie(currentMenu + " -top_in");
+ Movie *movieNextBottomIn = this->score->insertMovie(currentMenu + " -bottom_in");
+ Movie *movieShake = this->score->insertMovie(currentMenu + " -shake");
+
+ int i = 0;
+ while (!currentNode.isNull() && i < maxExamples){
+ TextButton *item;
+
+ // create normal menu button
+ QString label = currentNode.toElement().attribute("name");
+ item = new TextButton(label, TextButton::LEFT, type, this->window->scene, 0);
+ currentNode = currentNode.nextSibling();
+
+#ifndef QT_OPENGL_SUPPORT
+ if (currentNode.toElement().attribute("dirname") == "opengl")
+ currentNode = currentNode.nextSibling();
+#endif
+
+ item->setRecursiveVisible(false);
+ item->setZValue(10);
+ qreal ih = item->sceneBoundingRect().height();
+ qreal iw = item->sceneBoundingRect().width();
+ qreal ihp = ih + 3;
+
+ // create in-animation:
+ DemoItemAnimation *anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
+ anim->setDuration(float(1000 + (i * 20)) * Colors::animSpeedButtons);
+ anim->setStartPos(QPointF(xOffset, -ih));
+ anim->setPosAt(0.20, QPointF(xOffset, -ih));
+ anim->setPosAt(0.50, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY + (10 * float(i / 4.0f))));
+ anim->setPosAt(0.60, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+ anim->setPosAt(0.70, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY + (5 * float(i / 4.0f))));
+ anim->setPosAt(0.80, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+ anim->setPosAt(0.90, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY + (2 * float(i / 4.0f))));
+ anim->setPosAt(1.00, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+ movieIn->append(anim);
+
+ // create out-animation:
+ anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
+ anim->hideOnFinished = true;
+ anim->setDuration((700 + (30 * i)) * Colors::animSpeedButtons);
+ anim->setStartPos(QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+ anim->setPosAt(0.60, QPointF(xOffset, 600 - ih - ih));
+ anim->setPosAt(0.65, QPointF(xOffset + 20, 600 - ih));
+ anim->setPosAt(1.00, QPointF(sw + iw, 600 - ih));
+ movieOut->append(anim);
+
+ // create shake-animation:
+ anim = new DemoItemAnimation(item);
+ anim->setDuration(700 * Colors::animSpeedButtons);
+ anim->setStartPos(QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+ anim->setPosAt(0.55, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY - i*2.0));
+ anim->setPosAt(0.70, QPointF(xOffset - 10, (i * ihp) + yOffset + Colors::contentStartY - i*1.5));
+ anim->setPosAt(0.80, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY - i*1.0));
+ anim->setPosAt(0.90, QPointF(xOffset - 2, (i * ihp) + yOffset + Colors::contentStartY - i*0.5));
+ anim->setPosAt(1.00, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+ movieShake->append(anim);
+
+ // create next-menu top-out-animation:
+ anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
+ anim->hideOnFinished = true;
+ anim->setDuration((200 + (30 * i)) * Colors::animSpeedButtons);
+ anim->setStartPos(QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+ anim->setPosAt(0.70, QPointF(xOffset, yOffset + Colors::contentStartY));
+ anim->setPosAt(1.00, QPointF(-iw, yOffset + Colors::contentStartY));
+ movieNextTopOut->append(anim);
+
+ // create next-menu bottom-out-animation:
+ anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
+ anim->hideOnFinished = true;
+ anim->setDuration((200 + (30 * i)) * Colors::animSpeedButtons);
+ anim->setStartPos(QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+ anim->setPosAt(0.70, QPointF(xOffset, (maxExamples * ihp) + yOffset + Colors::contentStartY));
+ anim->setPosAt(1.00, QPointF(-iw, (maxExamples * ihp) + yOffset + Colors::contentStartY));
+ movieNextBottomOut->append(anim);
+
+ // create next-menu top-in-animation:
+ anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
+ anim->setDuration((700 - (30 * i)) * Colors::animSpeedButtons);
+ anim->setStartPos(QPointF(-iw, yOffset + Colors::contentStartY));
+ anim->setPosAt(0.30, QPointF(xOffset, yOffset + Colors::contentStartY));
+ anim->setPosAt(1.00, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+ movieNextTopIn->append(anim);
+
+ // create next-menu bottom-in-animation:
+ int reverse = maxExamples - i;
+ anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
+ anim->setDuration((1000 - (30 * reverse)) * Colors::animSpeedButtons);
+ anim->setStartPos(QPointF(-iw, (maxExamples * ihp) + yOffset + Colors::contentStartY));
+ anim->setPosAt(0.30, QPointF(xOffset, (maxExamples * ihp) + yOffset + Colors::contentStartY));
+ anim->setPosAt(1.00, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+ movieNextBottomIn->append(anim);
+
+ i++;
+ }
+
+ if (!currentNode.isNull() && i == maxExamples){
+ // We need another menu, so register for 'more' and 'back' buttons
+ ++menuIndex;
+ this->info[currentMenu]["more"] = name + QLatin1String(" -menu") + QString::number(menuIndex);
+ currentMenu = name + QLatin1String(" -menu") + QString::number(menuIndex);
+ this->info[currentMenu]["back"] = name + QLatin1String(" -menu") + QString::number(menuIndex - 1);
+ }
+ }
+}
+
+
+void MenuManager::createLowLeftButton(const QString &label, BUTTON_TYPE type,
+ Movie *movieIn, Movie *movieOut, Movie *movieShake, const QString &menuString)
+{
+ TextButton *button = new TextButton(label, TextButton::RIGHT, type, this->window->scene, 0, TextButton::PANEL);
+ if (!menuString.isNull())
+ button->setMenuString(menuString);
+ button->setRecursiveVisible(false);
+ button->setZValue(10);
+
+ qreal iw = button->sceneBoundingRect().width();
+ int xOffset = 15;
+
+ // create in-animation:
+ DemoItemAnimation *buttonIn = new DemoItemAnimation(button, DemoItemAnimation::ANIM_IN);
+ buttonIn->setDuration(1800 * Colors::animSpeedButtons);
+ buttonIn->setStartPos(QPointF(-iw, Colors::contentStartY + Colors::contentHeight - 35));
+ buttonIn->setPosAt(0.5, QPointF(-iw, Colors::contentStartY + Colors::contentHeight - 35));
+ buttonIn->setPosAt(0.7, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 35));
+ buttonIn->setPosAt(1.0, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 26));
+ movieIn->append(buttonIn);
+
+ // create out-animation:
+ DemoItemAnimation *buttonOut = new DemoItemAnimation(button, DemoItemAnimation::ANIM_OUT);
+ buttonOut->hideOnFinished = true;
+ buttonOut->setDuration(400 * Colors::animSpeedButtons);
+ buttonOut->setStartPos(QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 26));
+ buttonOut->setPosAt(1.0, QPointF(-iw, Colors::contentStartY + Colors::contentHeight - 26));
+ movieOut->append(buttonOut);
+
+ if (movieShake){
+ DemoItemAnimation *shakeAnim = new DemoItemAnimation(button, DemoItemAnimation::ANIM_UNSPECIFIED);
+ shakeAnim->timeline->setCurveShape(QTimeLine::LinearCurve);
+ shakeAnim->setDuration(650);
+ shakeAnim->setStartPos(buttonIn->posAt(1.0f));
+ shakeAnim->setPosAt(0.60, buttonIn->posAt(1.0f));
+ shakeAnim->setPosAt(0.70, buttonIn->posAt(1.0f) + QPointF(-3, 0));
+ shakeAnim->setPosAt(0.80, buttonIn->posAt(1.0f) + QPointF(2, 0));
+ shakeAnim->setPosAt(0.90, buttonIn->posAt(1.0f) + QPointF(-1, 0));
+ shakeAnim->setPosAt(1.00, buttonIn->posAt(1.0f));
+ movieShake->append(shakeAnim);
+ }
+}
+
+void MenuManager::createLowRightButton(const QString &label, BUTTON_TYPE type, Movie *movieIn, Movie *movieOut, Movie * /*movieShake*/)
+{
+ TextButton *item = new TextButton(label, TextButton::RIGHT, type, this->window->scene, 0, TextButton::PANEL);
+ item->setRecursiveVisible(false);
+ item->setZValue(10);
+
+ qreal sw = this->window->scene->sceneRect().width();
+ int xOffset = 70;
+
+ // create in-animation:
+ DemoItemAnimation *anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
+ anim->setDuration(1800 * Colors::animSpeedButtons);
+ anim->setStartPos(QPointF(sw, Colors::contentStartY + Colors::contentHeight - 35));
+ anim->setPosAt(0.5, QPointF(sw, Colors::contentStartY + Colors::contentHeight - 35));
+ anim->setPosAt(0.7, QPointF(xOffset + 535, Colors::contentStartY + Colors::contentHeight - 35));
+ anim->setPosAt(1.0, QPointF(xOffset + 535, Colors::contentStartY + Colors::contentHeight - 26));
+ movieIn->append(anim);
+
+ // create out-animation:
+ anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
+ anim->hideOnFinished = true;
+ anim->setDuration(400 * Colors::animSpeedButtons);
+ anim->setStartPos(QPointF(xOffset + 535, Colors::contentStartY + Colors::contentHeight - 26));
+ anim->setPosAt(1.0, QPointF(sw, Colors::contentStartY + Colors::contentHeight - 26));
+ movieOut->append(anim);
+}
+
+void MenuManager::createLowRightLeafButton(const QString &label, int xOffset, BUTTON_TYPE type, Movie *movieIn, Movie *movieOut, Movie * /*movieShake*/)
+{
+ TextButton *item = new TextButton(label, TextButton::RIGHT, type, this->window->scene, 0, TextButton::PANEL);
+ item->setRecursiveVisible(false);
+ item->setZValue(10);
+
+ qreal sw = this->window->scene->sceneRect().width();
+ qreal sh = this->window->scene->sceneRect().height();
+
+ // create in-animation:
+ DemoItemAnimation *anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
+ anim->setDuration(1050 * Colors::animSpeedButtons);
+ anim->setStartPos(QPointF(sw, Colors::contentStartY + Colors::contentHeight - 35));
+ anim->setPosAt(0.10, QPointF(sw, Colors::contentStartY + Colors::contentHeight - 35));
+ anim->setPosAt(0.30, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 35));
+ anim->setPosAt(0.35, QPointF(xOffset + 30, Colors::contentStartY + Colors::contentHeight - 35));
+ anim->setPosAt(0.40, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 35));
+ anim->setPosAt(0.45, QPointF(xOffset + 5, Colors::contentStartY + Colors::contentHeight - 35));
+ anim->setPosAt(0.50, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 35));
+ anim->setPosAt(1.00, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 26));
+ movieIn->append(anim);
+
+ // create out-animation:
+ anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
+ anim->hideOnFinished = true;
+ anim->setDuration(300 * Colors::animSpeedButtons);
+ anim->setStartPos(QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 26));
+ anim->setPosAt(1.0, QPointF(xOffset, sh));
+ movieOut->append(anim);
+}
+
+void MenuManager::createInfo(DemoItem *item, const QString &name)
+{
+ Movie *movie_in = this->score->insertMovie(name);
+ Movie *movie_out = this->score->insertMovie(name + " -out");
+ item->setZValue(8);
+ item->setRecursiveVisible(false);
+
+ float xOffset = 230.0f;
+ DemoItemAnimation *infoIn = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
+ infoIn->timeline->setCurveShape(QTimeLine::LinearCurve);
+ infoIn->setDuration(650);
+ infoIn->setStartPos(QPointF(this->window->scene->sceneRect().width(), Colors::contentStartY));
+ infoIn->setPosAt(0.60, QPointF(xOffset, Colors::contentStartY));
+ infoIn->setPosAt(0.70, QPointF(xOffset + 20, Colors::contentStartY));
+ infoIn->setPosAt(0.80, QPointF(xOffset, Colors::contentStartY));
+ infoIn->setPosAt(0.90, QPointF(xOffset + 7, Colors::contentStartY));
+ infoIn->setPosAt(1.00, QPointF(xOffset, Colors::contentStartY));
+ movie_in->append(infoIn);
+
+ DemoItemAnimation *infoOut = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
+ infoOut->timeline->setCurveShape(QTimeLine::EaseInCurve);
+ infoOut->setDuration(300);
+ infoOut->hideOnFinished = true;
+ infoOut->setStartPos(QPointF(xOffset, Colors::contentStartY));
+ infoOut->setPosAt(1.0, QPointF(-600, Colors::contentStartY));
+ movie_out->append(infoOut);
+}
+
+void MenuManager::createTicker()
+{
+ if (!Colors::noTicker){
+ Movie *movie_in = this->score->insertMovie("ticker");
+ Movie *movie_out = this->score->insertMovie("ticker -out");
+ Movie *movie_activate = this->score->insertMovie("ticker -activate");
+ Movie *movie_deactivate = this->score->insertMovie("ticker -deactivate");
+
+ this->ticker = new ItemCircleAnimation(this->window->scene, 0);
+ this->ticker->setZValue(50);
+ this->ticker->hide();
+
+ // Move ticker in:
+ int qtendpos = 485;
+ int qtPosY = 120;
+ this->tickerInAnim = new DemoItemAnimation(this->ticker, DemoItemAnimation::ANIM_IN);
+ this->tickerInAnim->setDuration(500);
+ this->tickerInAnim->setStartPos(QPointF(this->window->scene->sceneRect().width(), Colors::contentStartY + qtPosY));
+ this->tickerInAnim->setPosAt(0.60, QPointF(qtendpos, Colors::contentStartY + qtPosY));
+ this->tickerInAnim->setPosAt(0.70, QPointF(qtendpos + 30, Colors::contentStartY + qtPosY));
+ this->tickerInAnim->setPosAt(0.80, QPointF(qtendpos, Colors::contentStartY + qtPosY));
+ this->tickerInAnim->setPosAt(0.90, QPointF(qtendpos + 5, Colors::contentStartY + qtPosY));
+ this->tickerInAnim->setPosAt(1.00, QPointF(qtendpos, Colors::contentStartY + qtPosY));
+ movie_in->append(this->tickerInAnim);
+
+ // Move ticker out:
+ DemoItemAnimation *qtOut = new DemoItemAnimation(this->ticker, DemoItemAnimation::ANIM_OUT);
+ qtOut->hideOnFinished = true;
+ qtOut->setDuration(500);
+ qtOut->setStartPos(QPointF(qtendpos, Colors::contentStartY + qtPosY));
+ qtOut->setPosAt(1.00, QPointF(this->window->scene->sceneRect().width() + 700, Colors::contentStartY + qtPosY));
+ movie_out->append(qtOut);
+
+ // Move ticker in on activate:
+ DemoItemAnimation *qtActivate = new DemoItemAnimation(this->ticker);
+ qtActivate->setDuration(400);
+ qtActivate->setStartPos(QPointF(this->window->scene->sceneRect().width(), Colors::contentStartY + qtPosY));
+ qtActivate->setPosAt(0.60, QPointF(qtendpos, Colors::contentStartY + qtPosY));
+ qtActivate->setPosAt(0.70, QPointF(qtendpos + 30, Colors::contentStartY + qtPosY));
+ qtActivate->setPosAt(0.80, QPointF(qtendpos, Colors::contentStartY + qtPosY));
+ qtActivate->setPosAt(0.90, QPointF(qtendpos + 5, Colors::contentStartY + qtPosY));
+ qtActivate->setPosAt(1.00, QPointF(qtendpos, Colors::contentStartY + qtPosY));
+ movie_activate->append(qtActivate);
+
+ // Move ticker out on deactivate:
+ DemoItemAnimation *qtDeactivate = new DemoItemAnimation(this->ticker);
+ qtDeactivate->hideOnFinished = true;
+ qtDeactivate->setDuration(400);
+ qtDeactivate->setStartPos(QPointF(qtendpos, Colors::contentStartY + qtPosY));
+ qtDeactivate->setPosAt(1.00, QPointF(qtendpos, 800));
+ movie_deactivate->append(qtDeactivate);
+ }
+}
+
+void MenuManager::createUpnDownButtons()
+{
+ float xOffset = 15.0f;
+ float yOffset = 450.0f;
+
+ this->upButton = new TextButton("", TextButton::LEFT, MenuManager::UP, this->window->scene, 0, TextButton::UP);
+ this->upButton->prepare();
+ this->upButton->setPos(xOffset, yOffset);
+ this->upButton->setState(TextButton::DISABLED);
+
+ this->downButton = new TextButton("", TextButton::LEFT, MenuManager::DOWN, this->window->scene, 0, TextButton::DOWN);
+ this->downButton->prepare();
+ this->downButton->setPos(xOffset + 10 + this->downButton->sceneBoundingRect().width(), yOffset);
+
+ Movie *movieShake = this->score->insertMovie("upndown -shake");
+
+ DemoItemAnimation *shakeAnim = new DemoItemAnimation(this->upButton, DemoItemAnimation::ANIM_UNSPECIFIED);
+ shakeAnim->timeline->setCurveShape(QTimeLine::LinearCurve);
+ shakeAnim->setDuration(650);
+ shakeAnim->setStartPos(this->upButton->pos());
+ shakeAnim->setPosAt(0.60, this->upButton->pos());
+ shakeAnim->setPosAt(0.70, this->upButton->pos() + QPointF(-2, 0));
+ shakeAnim->setPosAt(0.80, this->upButton->pos() + QPointF(1, 0));
+ shakeAnim->setPosAt(0.90, this->upButton->pos() + QPointF(-1, 0));
+ shakeAnim->setPosAt(1.00, this->upButton->pos());
+ movieShake->append(shakeAnim);
+
+ shakeAnim = new DemoItemAnimation(this->downButton, DemoItemAnimation::ANIM_UNSPECIFIED);
+ shakeAnim->timeline->setCurveShape(QTimeLine::LinearCurve);
+ shakeAnim->setDuration(650);
+ shakeAnim->setStartPos(this->downButton->pos());
+ shakeAnim->setPosAt(0.60, this->downButton->pos());
+ shakeAnim->setPosAt(0.70, this->downButton->pos() + QPointF(-5, 0));
+ shakeAnim->setPosAt(0.80, this->downButton->pos() + QPointF(-3, 0));
+ shakeAnim->setPosAt(0.90, this->downButton->pos() + QPointF(-1, 0));
+ shakeAnim->setPosAt(1.00, this->downButton->pos());
+ movieShake->append(shakeAnim);
+}
+
+void MenuManager::createBackButton()
+{
+ Movie *backIn = this->score->insertMovie("back -in");
+ Movie *backOut = this->score->insertMovie("back -out");
+ Movie *backShake = this->score->insertMovie("back -shake");
+ createLowLeftButton(QLatin1String("Back"), ROOT, backIn, backOut, backShake, Colors::rootMenuName);
+}
diff --git a/demos/qtdemo/menumanager.h b/demos/qtdemo/menumanager.h
new file mode 100644
index 0000000..3a12c54
--- /dev/null
+++ b/demos/qtdemo/menumanager.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MENU_MANAGER_H
+#define MENU_MANAGER_H
+
+#include <QtGui>
+#include <QtXml>
+#include <QtHelp/QHelpEngineCore>
+
+#include "score.h"
+#include "textbutton.h"
+#include "mainwindow.h"
+#include "itemcircleanimation.h"
+
+typedef QHash<QString, QString> StringHash;
+typedef QHash<QString, StringHash> HashHash;
+
+class TextButton;
+
+class MenuManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum BUTTON_TYPE {ROOT, MENU1, MENU2, LAUNCH, DOCUMENTATION, QUIT, FULLSCREEN, UP, DOWN, BACK};
+
+ // singleton pattern:
+ static MenuManager *instance();
+ virtual ~MenuManager();
+
+ void init(MainWindow *window);
+ void itemSelected(int userCode, const QString &menuName = "");
+
+ QByteArray getHtml(const QString &name);
+ QByteArray getImage(const QString &name);
+ QString resolveExeFile(const QString &name);
+ QString resolveDocUrl(const QString &name);
+ QString resolveImageUrl(const QString &name);
+ QString resolveDataDir(const QString &name);
+
+ HashHash info;
+ ItemCircleAnimation *ticker;
+ MainWindow *window;
+ Score *score;
+ int currentMenuCode;
+
+private slots:
+ void exampleFinished();
+ void exampleError(QProcess::ProcessError error);
+
+private:
+ // singleton pattern:
+ MenuManager();
+ static MenuManager *pInstance;
+
+ QByteArray getResource(const QString &name);
+
+ void readXmlDocument();
+ void initHelpEngine();
+ void getDocumentationDir();
+ void readInfoAboutExample(const QDomElement &example);
+ void showDocInAssistant(const QString &docFile);
+ void launchExample(const QString &uniqueName);
+
+ void createMenu(const QDomElement &category, BUTTON_TYPE type);
+ void createLowLeftButton(const QString &label, BUTTON_TYPE type,
+ Movie *movieIn, Movie *movieOut, Movie *movieShake, const QString &menuString = QString());
+ void createLowRightButton(const QString &label, BUTTON_TYPE type, Movie *movieIn, Movie *movieOut, Movie *movieShake);
+ void createLowRightLeafButton(const QString &label, int pos, BUTTON_TYPE type, Movie *movieIn, Movie *movieOut, Movie * /*movieShake*/);
+ void createRootMenu(const QDomElement &el);
+ void createSubMenu(const QDomElement &el);
+ void createLeafMenu(const QDomElement &el);
+ void createInfo(DemoItem *item, const QString &name);
+ void createTicker();
+ void createUpnDownButtons();
+ void createBackButton();
+
+ QDomDocument *contentsDoc;
+ QProcess assistantProcess;
+ QString currentMenu;
+ QString currentCategory;
+ QString currentMenuButtons;
+ QString currentInfo;
+ QString helpRootUrl;
+ DemoItemAnimation *tickerInAnim;
+ QDir docDir;
+ QDir imgDir;
+ QHelpEngineCore *helpEngine;
+
+ TextButton *upButton;
+ TextButton *downButton;
+};
+
+#endif // MENU_MANAGER_H
+
diff --git a/demos/qtdemo/qtdemo.icns b/demos/qtdemo/qtdemo.icns
new file mode 100644
index 0000000..def5f0e
--- /dev/null
+++ b/demos/qtdemo/qtdemo.icns
Binary files differ
diff --git a/demos/qtdemo/qtdemo.ico b/demos/qtdemo/qtdemo.ico
new file mode 100644
index 0000000..016c77f
--- /dev/null
+++ b/demos/qtdemo/qtdemo.ico
Binary files differ
diff --git a/demos/qtdemo/qtdemo.pro b/demos/qtdemo/qtdemo.pro
new file mode 100644
index 0000000..18eac80
--- /dev/null
+++ b/demos/qtdemo/qtdemo.pro
@@ -0,0 +1,74 @@
+CONFIG += assistant help x11inc
+TARGET = qtdemo
+DESTDIR = $$QT_BUILD_TREE/bin
+OBJECTS_DIR = .obj
+MOC_DIR = .moc
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+QT += xml network
+
+contains(QT_CONFIG, opengl) {
+ DEFINES += QT_OPENGL_SUPPORT
+ QT += opengl
+}
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+RESOURCES = qtdemo.qrc
+HEADERS = mainwindow.h \
+ demoscene.h \
+ demoitem.h \
+ score.h \
+ demoitemanimation.h \
+ itemcircleanimation.h \
+ demotextitem.h \
+ headingitem.h \
+ dockitem.h \
+ scanitem.h \
+ letteritem.h \
+ examplecontent.h \
+ menucontent.h \
+ guide.h \
+ guideline.h \
+ guidecircle.h \
+ menumanager.h \
+ colors.h \
+ textbutton.h \
+ imageitem.h
+SOURCES = main.cpp \
+ demoscene.cpp \
+ mainwindow.cpp \
+ demoitem.cpp \
+ score.cpp \
+ demoitemanimation.cpp \
+ itemcircleanimation.cpp \
+ demotextitem.cpp \
+ headingitem.cpp \
+ dockitem.cpp \
+ scanitem.cpp \
+ letteritem.cpp \
+ examplecontent.cpp \
+ menucontent.cpp \
+ guide.cpp \
+ guideline.cpp \
+ guidecircle.cpp \
+ menumanager.cpp \
+ colors.cpp \
+ textbutton.cpp \
+ imageitem.cpp
+
+win32:RC_FILE = qtdemo.rc
+mac {
+ICON = qtdemo.icns
+QMAKE_INFO_PLIST = Info_mac.plist
+}
+
+# install
+target.path = $$[QT_INSTALL_BINS]
+sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES qtdemo.pro images xml *.ico *.icns *.rc *.plist
+sources.path = $$[QT_INSTALL_DEMOS]/qtdemo
+
diff --git a/demos/qtdemo/qtdemo.qrc b/demos/qtdemo/qtdemo.qrc
new file mode 100644
index 0000000..b30dd58
--- /dev/null
+++ b/demos/qtdemo/qtdemo.qrc
@@ -0,0 +1,8 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>xml/examples.xml</file>
+ <file>images/qtlogo_small.png</file>
+ <file>images/trolltech-logo.png</file>
+ <file>images/demobg.png</file>
+</qresource>
+</RCC>
diff --git a/demos/qtdemo/qtdemo.rc b/demos/qtdemo/qtdemo.rc
new file mode 100644
index 0000000..4cf2a63
--- /dev/null
+++ b/demos/qtdemo/qtdemo.rc
@@ -0,0 +1,2 @@
+IDI_ICON1 ICON DISCARDABLE "qtdemo.ico"
+
diff --git a/demos/qtdemo/scanitem.cpp b/demos/qtdemo/scanitem.cpp
new file mode 100644
index 0000000..0eab840
--- /dev/null
+++ b/demos/qtdemo/scanitem.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "scanitem.h"
+#include "colors.h"
+
+#define ITEM_WIDTH 16
+#define ITEM_HEIGHT 16
+
+ScanItem::ScanItem(QGraphicsScene *scene, QGraphicsItem *parent)
+ : DemoItem(scene, parent)
+{
+ useSharedImage(QString(__FILE__));
+}
+
+ScanItem::~ScanItem()
+{
+}
+
+QImage *ScanItem::createImage(const QMatrix &matrix) const
+{
+ QRect scaledRect = matrix.mapRect(QRect(0, 0, ITEM_WIDTH, ITEM_HEIGHT));
+ QImage *image = new QImage(scaledRect.width(), scaledRect.height(), QImage::Format_ARGB32_Premultiplied);
+ image->fill(QColor(0, 0, 0, 0).rgba());
+ QPainter painter(image);
+ painter.setRenderHint(QPainter::Antialiasing);
+
+ if (Colors::useEightBitPalette){
+ painter.setPen(QPen(QColor(100, 100, 100), 2));
+ painter.setBrush(QColor(206, 246, 117));
+ painter.drawEllipse(1, 1, scaledRect.width()-2, scaledRect.height()-2);
+ }
+ else {
+ painter.setPen(QPen(QColor(0, 0, 0, 15), 1));
+// painter.setBrush(QColor(206, 246, 117, 150));
+ painter.setBrush(QColor(0, 0, 0, 15));
+ painter.drawEllipse(1, 1, scaledRect.width()-2, scaledRect.height()-2);
+ }
+ return image;
+}
+
+
diff --git a/demos/qtdemo/scanitem.h b/demos/qtdemo/scanitem.h
new file mode 100644
index 0000000..b0b5ffc
--- /dev/null
+++ b/demos/qtdemo/scanitem.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SCAN_ITEM_H
+#define SCAN_ITEM_H
+
+#include <QtGui>
+#include "demoitem.h"
+
+class ScanItem : public DemoItem
+{
+public:
+ ScanItem(QGraphicsScene *scene = 0, QGraphicsItem *parent = 0);
+ virtual ~ScanItem();
+
+protected:
+ QImage *createImage(const QMatrix &matrix) const;
+
+};
+
+#endif // SCAN_ITEM_H
+
diff --git a/demos/qtdemo/score.cpp b/demos/qtdemo/score.cpp
new file mode 100644
index 0000000..f45ba0d
--- /dev/null
+++ b/demos/qtdemo/score.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "score.h"
+#include "colors.h"
+#include "demoitem.h"
+
+Score::Score()
+{
+}
+
+Score::~Score()
+{
+ // NB! Deleting all movies.
+ qDeleteAll(this->index);
+}
+
+void Score::prepare(Movie *movie, RUN_MODE runMode, LOCK_MODE lockMode)
+{
+ if (lockMode == LOCK_ITEMS){
+ for (int i=0; i<movie->size(); ++i){
+ if (runMode == ONLY_IF_VISIBLE && !movie->at(i)->demoItem()->isVisible())
+ continue;
+ movie->at(i)->lockItem(true);
+ movie->at(i)->prepare();
+ }
+ }
+ else if (lockMode == UNLOCK_ITEMS){
+ for (int i=0; i<movie->size(); ++i){
+ if (runMode == ONLY_IF_VISIBLE && !movie->at(i)->demoItem()->isVisible())
+ continue;
+ movie->at(i)->lockItem(false);
+ movie->at(i)->prepare();
+ }
+ }
+ else {
+ for (int i=0; i<movie->size(); ++i){
+ if (runMode == ONLY_IF_VISIBLE && !movie->at(i)->demoItem()->isVisible())
+ continue;
+ movie->at(i)->prepare();
+ }
+ }
+}
+
+void Score::play(Movie *movie, RUN_MODE runMode)
+{
+ if (runMode == NEW_ANIMATION_ONLY){
+ for (int i=0; i<movie->size(); ++i)
+ if (movie->at(i)->notOwnerOfItem())
+ movie->at(i)->play(true);
+ }
+ else if (runMode == ONLY_IF_VISIBLE){
+ for (int i=0; i<movie->size(); ++i)
+ if (movie->at(i)->demoItem()->isVisible())
+ movie->at(i)->play(runMode == FROM_START);
+ }
+ else {
+ for (int i=0; i<movie->size(); ++i)
+ movie->at(i)->play(runMode == FROM_START);
+ }
+}
+
+void Score::playMovie(const QString &indexName, RUN_MODE runMode, LOCK_MODE lockMode)
+{
+ MovieIndex::iterator movieIterator = this->index.find(indexName);
+ if (movieIterator == this->index.end())
+ return;
+
+ Movie *movie = *movieIterator;
+ this->prepare(movie, runMode, lockMode);
+ this->play(movie, runMode);
+}
+
+void Score::queueMovie(const QString &indexName, RUN_MODE runMode, LOCK_MODE lockMode)
+{
+ MovieIndex::iterator movieIterator = this->index.find(indexName);
+ if (movieIterator == this->index.end()){
+ if (Colors::verbose)
+ qDebug() << "Queuing movie:" << indexName << "(does not exist)";
+ return;
+ }
+
+ Movie *movie = *movieIterator;
+ this->prepare(movie, runMode, lockMode);
+ this->playList.append(PlayListMember(movie, int(runMode)));
+ if (Colors::verbose)
+ qDebug() << "Queuing movie:" << indexName;
+}
+
+void Score::playQue()
+{
+ int movieCount = this->playList.size();
+ for (int i=0; i<movieCount; i++)
+ this->play(this->playList.at(i).movie, RUN_MODE(this->playList.at(i).runMode));
+ this->playList.clear();
+ if (Colors::verbose)
+ qDebug() << "********* Playing que *********";
+}
+
+void Score::insertMovie(const QString &indexName, Movie *movie)
+{
+ this->index.insert(indexName, movie);
+}
+
+Movie *Score::insertMovie(const QString &indexName)
+{
+ Movie *movie = new Movie();
+ insertMovie(indexName, movie);
+ return movie;
+}
+
diff --git a/demos/qtdemo/score.h b/demos/qtdemo/score.h
new file mode 100644
index 0000000..bfed5d2
--- /dev/null
+++ b/demos/qtdemo/score.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SCORE_H
+#define SCORE_H
+
+#include <QList>
+#include <QHash>
+#include "demoitemanimation.h"
+
+typedef QList<DemoItemAnimation *> Movie;
+typedef QHash<QString, Movie*> MovieIndex;
+
+class PlayListMember
+{
+public:
+ PlayListMember(Movie *movie, int runMode) : movie(movie), runMode(runMode){};
+ Movie *movie;
+ int runMode;
+};
+typedef QList<PlayListMember> PlayList;
+
+class Score
+{
+public:
+ enum LOCK_MODE {LOCK_ITEMS, UNLOCK_ITEMS, SKIP_LOCK};
+ enum RUN_MODE {FROM_CURRENT, FROM_START, NEW_ANIMATION_ONLY, ONLY_IF_VISIBLE};
+
+ Score();
+ virtual ~Score();
+
+ void playMovie(const QString &indexName, RUN_MODE runMode = FROM_START, LOCK_MODE lockMode = SKIP_LOCK);
+ void insertMovie(const QString &indexName, Movie *movie);
+ Movie *insertMovie(const QString &indexName);
+ void queueMovie(const QString &indexName, RUN_MODE runMode = FROM_START, LOCK_MODE lockMode = SKIP_LOCK);
+ void playQue();
+ bool hasQueuedMovies(){ return this->playList.size() > 0; };
+
+ MovieIndex index;
+ PlayList playList;
+
+private:
+ void prepare(Movie *movie, RUN_MODE runMode, LOCK_MODE lockMode);
+ void play(Movie *movie, RUN_MODE runMode);
+};
+
+#endif // SCORE_H
+
diff --git a/demos/qtdemo/textbutton.cpp b/demos/qtdemo/textbutton.cpp
new file mode 100644
index 0000000..96e1a23
--- /dev/null
+++ b/demos/qtdemo/textbutton.cpp
@@ -0,0 +1,384 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "textbutton.h"
+#include "demoitemanimation.h"
+#include "demotextitem.h"
+#include "colors.h"
+#include "menumanager.h"
+
+#define BUTTON_WIDTH 180
+#define BUTTON_HEIGHT 19
+
+class ButtonBackground : public DemoItem
+{
+public:
+ TextButton::BUTTONTYPE type;
+ bool highlighted;
+ bool pressed;
+ QSize logicalSize;
+
+ ButtonBackground(TextButton::BUTTONTYPE type, bool highlighted, bool pressed, QSize logicalSize,
+ QGraphicsScene *scene, QGraphicsItem *parent) : DemoItem(scene, parent)
+ {
+ this->type = type;
+ this->highlighted = highlighted;
+ this->pressed = pressed;
+ this->logicalSize = logicalSize;
+ useSharedImage(QString(__FILE__) + static_cast<int>(type) + highlighted + pressed);
+ }
+
+protected:
+ QImage *createImage(const QMatrix &matrix) const
+ {
+ if (type == TextButton::SIDEBAR || type == TextButton::PANEL)
+ return createRoundButtonBackground(matrix);
+ else
+ return createArrowBackground(matrix);
+ }
+
+ QImage *createRoundButtonBackground(const QMatrix &matrix) const
+ {
+ QRect scaledRect;
+ scaledRect = matrix.mapRect(QRect(0, 0, this->logicalSize.width(), this->logicalSize.height()));
+
+ QImage *image = new QImage(scaledRect.width(), scaledRect.height(), QImage::Format_ARGB32_Premultiplied);
+ image->fill(QColor(0, 0, 0, 0).rgba());
+ QPainter painter(image);
+ painter.setRenderHint(QPainter::SmoothPixmapTransform);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.setPen(Qt::NoPen);
+
+ if (Colors::useEightBitPalette){
+ painter.setPen(QColor(120, 120, 120));
+ if (this->pressed)
+ painter.setBrush(QColor(60, 60, 60));
+ else if (this->highlighted)
+ painter.setBrush(QColor(100, 100, 100));
+ else
+ painter.setBrush(QColor(80, 80, 80));
+ }
+ else {
+ QLinearGradient outlinebrush(0, 0, 0, scaledRect.height());
+ QLinearGradient brush(0, 0, 0, scaledRect.height());
+
+ brush.setSpread(QLinearGradient::PadSpread);
+ QColor highlight(255, 255, 255, 70);
+ QColor shadow(0, 0, 0, 70);
+ QColor sunken(220, 220, 220, 30);
+ QColor normal1(255, 255, 245, 60);
+ QColor normal2(255, 255, 235, 10);
+
+ if (this->type == TextButton::PANEL){
+ normal1 = QColor(200, 170, 160, 50);
+ normal2 = QColor(50, 10, 0, 50);
+ }
+
+ if (pressed) {
+ outlinebrush.setColorAt(0.0f, shadow);
+ outlinebrush.setColorAt(1.0f, highlight);
+ brush.setColorAt(0.0f, sunken);
+ painter.setPen(Qt::NoPen);
+ } else {
+ outlinebrush.setColorAt(1.0f, shadow);
+ outlinebrush.setColorAt(0.0f, highlight);
+ brush.setColorAt(0.0f, normal1);
+ if (!this->highlighted)
+ brush.setColorAt(1.0f, normal2);
+ painter.setPen(QPen(outlinebrush, 1));
+ }
+ painter.setBrush(brush);
+ }
+
+ if (this->type == TextButton::PANEL)
+ painter.drawRect(0, 0, scaledRect.width(), scaledRect.height());
+ else
+ painter.drawRoundedRect(0, 0, scaledRect.width(), scaledRect.height(), 10, 90, Qt::RelativeSize);
+ return image;
+ }
+
+ QImage *createArrowBackground(const QMatrix &matrix) const
+ {
+ QRect scaledRect;
+ scaledRect = matrix.mapRect(QRect(0, 0, this->logicalSize.width(), this->logicalSize.height()));
+
+ QImage *image = new QImage(scaledRect.width(), scaledRect.height(), QImage::Format_ARGB32_Premultiplied);
+ image->fill(QColor(0, 0, 0, 0).rgba());
+ QPainter painter(image);
+ painter.setRenderHint(QPainter::SmoothPixmapTransform);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.setPen(Qt::NoPen);
+
+ if (Colors::useEightBitPalette){
+ painter.setPen(QColor(120, 120, 120));
+ if (this->pressed)
+ painter.setBrush(QColor(60, 60, 60));
+ else if (this->highlighted)
+ painter.setBrush(QColor(100, 100, 100));
+ else
+ painter.setBrush(QColor(80, 80, 80));
+ }
+ else {
+ QLinearGradient outlinebrush(0, 0, 0, scaledRect.height());
+ QLinearGradient brush(0, 0, 0, scaledRect.height());
+
+ brush.setSpread(QLinearGradient::PadSpread);
+ QColor highlight(255, 255, 255, 70);
+ QColor shadow(0, 0, 0, 70);
+ QColor sunken(220, 220, 220, 30);
+ QColor normal1 = QColor(200, 170, 160, 50);
+ QColor normal2 = QColor(50, 10, 0, 50);
+
+ if (pressed) {
+ outlinebrush.setColorAt(0.0f, shadow);
+ outlinebrush.setColorAt(1.0f, highlight);
+ brush.setColorAt(0.0f, sunken);
+ painter.setPen(Qt::NoPen);
+ } else {
+ outlinebrush.setColorAt(1.0f, shadow);
+ outlinebrush.setColorAt(0.0f, highlight);
+ brush.setColorAt(0.0f, normal1);
+ if (!this->highlighted)
+ brush.setColorAt(1.0f, normal2);
+ painter.setPen(QPen(outlinebrush, 1));
+ }
+ painter.setBrush(brush);
+ }
+
+ painter.drawRect(0, 0, scaledRect.width(), scaledRect.height());
+
+ float xOff = scaledRect.width() / 2;
+ float yOff = scaledRect.height() / 2;
+ float sizex = 3.0f * matrix.m11();
+ float sizey = 1.5f * matrix.m22();
+ if (this->type == TextButton::UP)
+ sizey *= -1;
+ QPainterPath path;
+ path.moveTo(xOff, yOff + (5 * sizey));
+ path.lineTo(xOff - (4 * sizex), yOff - (3 * sizey));
+ path.lineTo(xOff + (4 * sizex), yOff - (3 * sizey));
+ path.lineTo(xOff, yOff + (5 * sizey));
+ painter.drawPath(path);
+
+ return image;
+ }
+
+};
+
+TextButton::TextButton(const QString &text, ALIGNMENT align, int userCode,
+ QGraphicsScene *scene, QGraphicsItem *parent, BUTTONTYPE type)
+ : DemoItem(scene, parent)
+{
+ this->menuString = text;
+ this->buttonLabel = text;
+ this->alignment = align;
+ this->buttonType = type;
+ this->userCode = userCode;
+ this->bgOn = 0;
+ this->bgOff = 0;
+ this->bgHighlight = 0;
+ this->bgDisabled = 0;
+ this->state = OFF;
+
+ this->setAcceptsHoverEvents(true);
+ this->setCursor(Qt::PointingHandCursor);
+
+ // Calculate button size:
+ const int w = 180;
+ const int h = 19;
+ if (type == SIDEBAR || type == PANEL)
+ this->logicalSize = QSize(w, h);
+ else
+ this->logicalSize = QSize(int((w / 2.0f) - 5), int(h * 1.5f));
+}
+
+void TextButton::setMenuString(const QString &menu)
+{
+ this->menuString = menu;
+}
+
+void TextButton::prepare()
+{
+ if (!this->prepared){
+ this->prepared = true;
+ this->setupHoverText();
+ this->setupScanItem();
+ this->setupButtonBg();
+ }
+}
+
+TextButton::~TextButton()
+{
+ if (this->prepared){
+ if (Colors::useButtonBalls)
+ delete this->scanAnim;
+ }
+}
+
+QRectF TextButton::boundingRect() const
+{
+ return QRectF(0, 0, this->logicalSize.width(), this->logicalSize.height());
+};
+
+void TextButton::setupHoverText()
+{
+ if (this->buttonLabel.isEmpty())
+ return;
+
+ DemoTextItem *textItem = new DemoTextItem(this->buttonLabel, Colors::buttonFont(), Colors::buttonText, -1, this->scene(), this);
+ textItem->setZValue(zValue() + 2);
+ textItem->setPos(16, 0);
+}
+
+void TextButton::setupScanItem()
+{
+ if (Colors::useButtonBalls){
+ ScanItem *scanItem = new ScanItem(0, this);
+ scanItem->setZValue(zValue() + 1);
+
+ this->scanAnim = new DemoItemAnimation(scanItem);
+ this->scanAnim->timeline->setLoopCount(1);
+
+ float x = 1;
+ float y = 1.5f;
+ float stop = BUTTON_WIDTH - scanItem->boundingRect().width() - x;
+ if (this->alignment == LEFT){
+ this->scanAnim->setDuration(2500);
+ this->scanAnim->setPosAt(0.0, QPointF(x, y));
+ this->scanAnim->setPosAt(0.5, QPointF(x, y));
+ this->scanAnim->setPosAt(0.7, QPointF(stop, y));
+ this->scanAnim->setPosAt(1.0, QPointF(x, y));
+ scanItem->setPos(QPointF(x, y));
+ }
+ else {
+ this->scanAnim->setPosAt(0.0, QPointF(stop, y));
+ this->scanAnim->setPosAt(0.5, QPointF(x, y));
+ this->scanAnim->setPosAt(1.0, QPointF(stop, y));
+ scanItem->setPos(QPointF(stop, y));
+ }
+ }
+}
+
+void TextButton::setState(STATE state)
+{
+ this->state = state;
+ this->bgOn->setRecursiveVisible(state == ON);
+ this->bgOff->setRecursiveVisible(state == OFF);
+ this->bgHighlight->setRecursiveVisible(state == HIGHLIGHT);
+ this->bgDisabled->setRecursiveVisible(state == DISABLED);
+ this->setCursor(state == DISABLED ? Qt::ArrowCursor : Qt::PointingHandCursor);
+
+}
+
+void TextButton::setupButtonBg()
+{
+ this->bgOn = new ButtonBackground(this->buttonType, true, true, this->logicalSize, this->scene(), this);
+ this->bgOff = new ButtonBackground(this->buttonType, false, false, this->logicalSize, this->scene(), this);
+ this->bgHighlight = new ButtonBackground(this->buttonType, true, false, this->logicalSize, this->scene(), this);
+ this->bgDisabled = new ButtonBackground(this->buttonType, true, true, this->logicalSize, this->scene(), this);
+ this->setState(OFF);
+}
+
+void TextButton::hoverEnterEvent(QGraphicsSceneHoverEvent *)
+{
+ if (this->locked || this->state == DISABLED)
+ return;
+
+ if (this->state == OFF){
+ this->setState(HIGHLIGHT);
+
+ if (Colors::noAnimations && Colors::useButtonBalls){
+ // wait a bit in the beginning
+ // to enhance the effect. Have to this here
+ // so that the adaption can be dynamic
+ this->scanAnim->setDuration(1000);
+ this->scanAnim->setPosAt(0.2, this->scanAnim->posAt(0));
+ }
+
+ if (MenuManager::instance()->window->fpsMedian > 10
+ || Colors::noAdapt
+ || Colors::noTimerUpdate){
+ if (Colors::useButtonBalls)
+ this->scanAnim->play(true, true);
+ }
+ }
+}
+
+void TextButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+ if (this->state == DISABLED)
+ return;
+
+ this->setState(OFF);
+
+ if (Colors::noAnimations && Colors::useButtonBalls)
+ this->scanAnim->stop();
+}
+
+void TextButton::mousePressEvent(QGraphicsSceneMouseEvent *)
+{
+ if (this->state == DISABLED)
+ return;
+
+ if (this->state == HIGHLIGHT || this->state == OFF)
+ this->setState(ON);
+}
+
+void TextButton::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (this->state == ON){
+ this->setState(OFF);
+ if (!this->locked && this->boundingRect().contains(event->pos())){
+ MenuManager::instance()->itemSelected(this->userCode, this->menuString);
+ }
+ }
+}
+
+void TextButton::animationStarted(int)
+{
+ if (this->state == DISABLED)
+ return;
+ this->setState(OFF);
+}
+
+
+
diff --git a/demos/qtdemo/textbutton.h b/demos/qtdemo/textbutton.h
new file mode 100644
index 0000000..b7c91fb
--- /dev/null
+++ b/demos/qtdemo/textbutton.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXT_BUTTON_H
+#define TEXT_BUTTON_H
+
+#include <QtGui>
+#include "demoitem.h"
+#include "demotextitem.h"
+#include "scanitem.h"
+
+class DemoItemAnimation;
+class ButtonBackground;
+
+class TextButton : public DemoItem
+{
+public:
+ enum ALIGNMENT {LEFT, RIGHT};
+ enum BUTTONTYPE {SIDEBAR, PANEL, UP, DOWN};
+ enum STATE {ON, OFF, HIGHLIGHT, DISABLED};
+
+ TextButton(const QString &text, ALIGNMENT align = LEFT, int userCode = 0,
+ QGraphicsScene *scene = 0, QGraphicsItem *parent = 0, BUTTONTYPE color = SIDEBAR);
+ virtual ~TextButton();
+
+ // overidden methods:
+ virtual QRectF boundingRect() const;
+ virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0){};
+ virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+
+ void animationStarted(int id = 0);
+ void prepare();
+ void setState(STATE state);
+ void setMenuString(const QString &menu);
+ void setDisabled(bool disabled);
+
+private:
+ void setupButtonBg();
+ void setupScanItem();
+ void setupHoverText();
+
+ DemoItemAnimation *scanAnim;
+ ButtonBackground *bgOn;
+ ButtonBackground *bgOff;
+ ButtonBackground *bgHighlight;
+ ButtonBackground *bgDisabled;
+
+ BUTTONTYPE buttonType;
+ ALIGNMENT alignment;
+ QString buttonLabel;
+ QString menuString;
+ int userCode;
+ QSize logicalSize;
+
+ STATE state;
+};
+
+#endif // TEXT_BUTTON_H
+
diff --git a/demos/qtdemo/xml/examples.xml b/demos/qtdemo/xml/examples.xml
new file mode 100644
index 0000000..df2d93b
--- /dev/null
+++ b/demos/qtdemo/xml/examples.xml
@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<categories name="Qt Examples and Demos">
+ <demos dirname="." docname="demos" name="Demonstrations">
+ <example filename="affine" name="Affine Transformations" />
+ <example filename="arthurplugin" name="Arthur Plugin" executable="false" />
+ <example filename="composition" name="Composition Modes" />
+ <example filename="gradients" name="Gradients" />
+ <example filename="pathstroke" name="Path Stroking" />
+ <example filename="deform" name="Vector Deformation" />
+ <example filename="books" name="Books" />
+ <example filename="mainwindow" name="Main Window" />
+ <example filename="spreadsheet" name="Spreadsheet" />
+ <example filename="sqlbrowser" name="SQL Browser" />
+ <example filename="textedit" name="Text Edit" />
+ <example filename="chip" name="40000 Chips" />
+ <example filename="embeddeddialogs" name="Embedded Dialogs" />
+ <example filename="interview" name="Interview" />
+ <example filename="browser" name="Browser" />
+ <example filename="mediaplayer" name="Media Player" />
+ <example filename="boxes" name="Boxes" />
+ </demos>
+ <category dirname="qtconcurrent" name="Concurrent Programming">
+ <example filename="map" name="Map" executable="false" />
+ <example filename="progressdialog" name="Progress Dialog" />
+ <example filename="runfunction" name="Run Function" executable="false"/>
+ <example filename="wordcount" name="Word Count" executable="false" />
+ </category>
+ <category dirname="designer" name="Qt Designer">
+ <example filename="calculatorbuilder" name="Calculator Builder" />
+ <example filename="calculatorform" name="Calculator Form" />
+ <example filename="containerextension" name="Container Extension" executable="false"/>
+ <example filename="customwidgetplugin" name="Custom Widget Plugin" executable="false" />
+ <example filename="taskmenuextension" name="Task Menu Extension" executable="false" />
+ <example filename="worldtimeclockbuilder" name="World Time Clock Builder" />
+ <example filename="worldtimeclockplugin" name="World Time Clock Plugin" executable="false"/>
+ </category>
+ <category dirname="desktop" name="Desktop">
+ <example filename="systray" name="System Tray" image="systemtray-example.png"/>
+ <example filename="screenshot" name="Screenshot" />
+ </category>
+ <category dirname="dialogs" name="Dialogs">
+ <example filename="configdialog" name="Configuration Dialog" />
+ <example filename="extension" name="Extension Dialog" />
+ <example filename="findfiles" name="Find Files Dialog" />
+ <example filename="standarddialogs" name="Standard Dialogs" />
+ <example filename="tabdialog" name="Tab Dialog" />
+ <example filename="trivialwizard" name="Trivial Wizard" image="trivialwizard-example-introduction.png"/>
+ <example filename="licensewizard" name="License Wizard" />
+ <example filename="classwizard" name="Class Wizard" />
+ </category>
+ <category dirname="draganddrop" name="Drag and Drop">
+ <example filename="draggableicons" name="Draggable Icons" />
+ <example filename="draggabletext" name="Draggable Text" />
+ <example filename="dropsite" name="Drop Site" />
+ <example filename="fridgemagnets" name="Fridge Magnets" />
+ <example filename="puzzle" name="Puzzle" image="draganddroppuzzle-example.png"/>
+ </category>
+ <category dirname="graphicsview" name="Graphics View">
+ <example filename="elasticnodes" name="Elastic Nodes" />
+ <example filename="collidingmice" name="Colliding Mice" />
+ <example filename="diagramscene" name="Diagram Scene" />
+ <example filename="dragdroprobot" name="Drag and Drop Robot" />
+ <example filename="portedcanvas" name="Ported Canvas" />
+ <example filename="portedasteroids" name="Ported Asteroids" />
+ <example filename="padnavigator" name="Pad Navigator Example" />
+ </category>
+ <category dirname="ipc" name="IPC">
+ <example filename="sharedmemory" name="Shared Memory" image="sharedmemory-example_1.png"/>
+ <example filename="localfortuneclient" name="Local Fortune Client" image="localfortuneclient-example.png"/>
+ <example filename="localfortuneserver" name="Local Fortune Server" image="localfortuneserver-example.png"/>
+ </category>
+ <category dirname="itemviews" name="Item Views">
+ <example filename="addressbook" name="Address Book" />
+ <example filename="basicsortfiltermodel" name="Basic Sort/Filter Model" />
+ <example filename="chart" name="Chart" />
+ <example filename="customsortfiltermodel" name="Custom Sort/Filter Model" />
+ <example filename="coloreditorfactory" name="Color Editor Factory" image="coloreditorfactoryimage.png"/>
+ <example filename="combowidgetmapper" name="Combo Widget Mapper" />
+ <example filename="dirview" name="Directory View" />
+ <example filename="fetchmore" name="Fetch More" />
+ <example filename="pixelator" name="Pixelator" />
+ <example filename="puzzle" name="Puzzle " image="itemviewspuzzle-example.png"/>
+ <example filename="simpledommodel" name="Simple DOM Model" />
+ <example filename="simpletreemodel" name="Simple Tree Model" />
+ <example filename="simplewidgetmapper" name="Simple Widget Mapper" />
+ <example filename="spinboxdelegate" name="Spin Box Delegate" />
+ <example filename="stardelegate" name="Star Delegate" />
+ </category>
+ <category dirname="layouts" name="Layouts">
+ <example filename="basiclayouts" name="Basic Layouts" />
+ <example filename="borderlayout" name="Border Layout" />
+ <example filename="dynamiclayouts" name="Dynamic Layouts" />
+ <example filename="flowlayout" name="Flow Layout" />
+ </category>
+ <category dirname="linguist" name="Qt Linguist">
+ <example filename="arrowpad" name="Arrow Pad" image="linguist-arrowpad_en.png"/>
+ <example filename="hellotr" name="Hello World" image="linguist-hellotr_en.png"/>
+ <example filename="trollprint" name="Troll Print" image="linguist-trollprint_10_en.png"/>
+ </category>
+ <category dirname="mainwindows" name="Main Windows">
+ <example filename="application" name="Application" />
+ <example filename="dockwidgets" name="Dock Widgets" />
+ <example filename="mdi" name="MDI" />
+ <example filename="sdi" name="SDI" />
+ <example filename="menus" name="Menus" />
+ <example filename="recentfiles" name="Recent Files" />
+ </category>
+ <category dirname="network" name="Networking">
+ <example filename="blockingfortuneclient" name="Blocking Fortune Client" />
+ <example filename="broadcastreceiver" name="Broadcast Receiver" />
+ <example filename="broadcastsender" name="Broadcast Sender" />
+ <example filename="network-chat" name="Network Chat Client" />
+ <example filename="fortuneclient" name="Fortune Client" />
+ <example filename="fortuneserver" name="Fortune Server" />
+ <example filename="ftp" changedirectory="false" name="FTP Client" />
+ <example filename="http" changedirectory="false" name="HTTP Client" />
+ <example filename="loopback" name="Loopback" />
+ <example filename="threadedfortuneserver" name="Threaded Fort. Server" />
+ <example filename="torrent" name="Torrent Client" />
+ <example filename="securesocketclient" name="Secure Socket Client" />
+ </category>
+ <category dirname="opengl" name="OpenGL">
+ <example filename="2dpainting" name="2D Painting" />
+ <example filename="framebufferobject" name="Framebuffer Object" />
+ <example filename="framebufferobject2" name="Framebuffer Object 2" />
+ <example filename="grabber" name="Grabber" />
+ <example filename="hellogl" name="Hello GL" />
+ <example filename="overpainting" name="Overpainting" />
+ <example filename="pbuffers" name="Pixel Buffers" />
+ <example filename="pbuffers2" name="Pixel Buffers 2" />
+ <example filename="samplebuffers" name="Sample Buffers" />
+ <example filename="textures" name="Textures" />
+ </category>
+ <category dirname="painting" name="Painting">
+ <example filename="basicdrawing" name="Basic Drawing" />
+ <example filename="concentriccircles" name="Concentric Circles" />
+ <example filename="fontsampler" name="Font Sampler" />
+ <example filename="imagecomposition" name="Image Composition" />
+ <example filename="painterpaths" name="Painter Paths" />
+ <example filename="svgviewer" name="SVG Viewer" />
+ <example filename="transformations" name="Transformations" />
+ </category>
+ <category dirname="phonon" name="Phonon">
+ <example filename="musicplayer" name="Music Player" />
+ </category>
+ <category dirname="richtext" name="Rich Text">
+ <example filename="calendar" name="Calendar" />
+ <example filename="orderform" name="Order Form" />
+ <example filename="syntaxhighlighter" name="Syntax Highlighter" />
+ <example filename="textobject" name="Text Object" />
+ </category>
+ <category dirname="script" name="QtScript">
+ <example filename="calculator" name="Calculator" />
+ <example filename="context2d" name="Context2D" />
+ <example filename="defaultprototypes" name="Default Prototypes" />
+ <example filename="helloscript" name="Hello Script" image="t1.png"/>
+ <example filename="qstetrix" name="QSTetrix" image="tetrix-example.png" />
+ </category>
+ <category dirname="sql" name="SQL">
+ <example filename="cachedtable" name="Cached Table" />
+ <example filename="drilldown" name="Drill Down" />
+ <example filename="querymodel" name="Query Model" />
+ <example filename="relationaltablemodel" name="Relational Table Model" />
+ <example filename="tablemodel" name="Table Model" />
+ <example filename="masterdetail" name="Music Archive" />
+ <example filename="sqlwidgetmapper" name="SQL Widget Mapper" />
+ </category>
+ <category dirname="threads" name="Threading">
+ <example filename="mandelbrot" name="Mandelbrot" />
+ </category>
+ <category dirname="tools" name="Tools">
+ <example filename="codecs" name="Codecs" />
+ <example filename="completer" name="Completer" />
+ <example filename="customcompleter" name="Custom Completer" />
+ <example filename="i18n" name="Internationalization" />
+ <example filename="plugandpaint" name="Plug and Paint" />
+ <example filename="regexp" name="Regular Expressions" />
+ <example filename="settingseditor" name="Settings Editor" />
+ <example filename="treemodelcompleter" name="Tree Model Completer" />
+ <example filename="undoframework" name="Undo Framework"/>
+ </category>
+ <category dirname="tutorials/addressbook" name="Address Book Tutorial">
+ <example filename="part1" name="Part 1" image="addressbook-tutorial-part1-screenshot.png" />
+ <example filename="part2" name="Part 2" image="addressbook-tutorial-part2-add-contact.png" />
+ <example filename="part3" name="Part 3" image="addressbook-tutorial-part3-screenshot.png" />
+ <example filename="part4" name="Part 4" image="addressbook-tutorial-screenshot.png" />
+ <example filename="part5" name="Part 5" image="addressbook-tutorial-part5-screenshot.png" />
+ <example filename="part6" name="Part 6" image="addressbook-tutorial-part6-screenshot.png" />
+ <example filename="part7" name="Part 7" image="addressbook-tutorial-part7-screenshot.png" />
+ </category>
+ <category dirname="widgets" name="Widgets">
+ <example filename="analogclock" name="Analog Clock" />
+ <example filename="calculator" name="Calculator " />
+ <example filename="calendarwidget" name="Calendar Widget" />
+ <example filename="charactermap" name="Character Map" />
+ <example filename="codeeditor" name="Code Editor" />
+ <example filename="digitalclock" name="Digital Clock" />
+ <example filename="groupbox" name="Group Box" />
+ <example filename="icons" name="Icons" />
+ <example filename="imageviewer" name="Image Viewer" />
+ <example filename="lineedits" name="Line Edits" />
+ <example filename="movie" name="Movie Player" />
+ <example filename="scribble" name="Scribble" />
+ <example filename="shapedclock" name="Shaped Clock" />
+ <example filename="sliders" name="Sliders" />
+ <example filename="spinboxes" name="Spin Boxes" />
+ <example filename="styles" name="Styles" image="styles-enabledwood.png"/>
+ <example filename="stylesheet" name="Style Sheet" image="stylesheet-coffee-plastique.png"/>
+ <example filename="tablet" name="Tablet" />
+ <example filename="tetrix" name="Tetrix " />
+ <example filename="tooltips" name="Tool Tips" />
+ <example filename="wiggly" name="Wiggly" />
+ <example filename="windowflags" name="Window Flags" />
+ </category>
+ <category dirname="xml" name="XML">
+ <example filename="saxbookmarks" name="SAX Bookmarks" />
+ <example filename="dombookmarks" name="DOM Bookmarks" />
+ <example filename="rsslisting" name="RSS-Listing" />
+ <example filename="streambookmarks" name="QXmlStream Bookmarks" image="xmlstreamexample-screenshot.png"/>
+ </category>
+ <category dirname="xmlpatterns" name="XML Patterns">
+ <example filename="recipes" name="Recipes" />
+ <example filename="qobjectxmlmodel" name="QObjectXmlModel" />
+ <example filename="filetree" name="File Tree" />
+ <example filename="trafficinfo" name="Traffic Info" />
+ </category>
+</categories>
diff --git a/demos/shared/arthurstyle.cpp b/demos/shared/arthurstyle.cpp
new file mode 100644
index 0000000..846d2f3
--- /dev/null
+++ b/demos/shared/arthurstyle.cpp
@@ -0,0 +1,452 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "arthurstyle.h"
+#include "arthurwidgets.h"
+#include <QLayout>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPixmapCache>
+#include <QRadioButton>
+#include <QString>
+#include <QStyleOption>
+#include <QtDebug>
+
+QPixmap cached(const QString &img)
+{
+ if (QPixmap *p = QPixmapCache::find(img))
+ return *p;
+
+ QPixmap pm;
+ pm = QPixmap::fromImage(QImage(img), Qt::OrderedDither | Qt::OrderedAlphaDither);
+ if (pm.isNull())
+ return QPixmap();
+
+ QPixmapCache::insert(img, pm);
+ return pm;
+}
+
+
+ArthurStyle::ArthurStyle()
+ : QWindowsStyle()
+{
+ Q_INIT_RESOURCE(shared);
+}
+
+
+void ArthurStyle::drawHoverRect(QPainter *painter, const QRect &r) const
+{
+ qreal h = r.height();
+ qreal h2 = r.height() / qreal(2);
+ QPainterPath path;
+ path.addRect(r.x() + h2, r.y() + 0, r.width() - h2 * 2, r.height());
+ path.addEllipse(r.x(), r.y(), h, h);
+ path.addEllipse(r.x() + r.width() - h, r.y(), h, h);
+ path.setFillRule(Qt::WindingFill);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(QColor(191, 215, 191));
+ painter->setRenderHint(QPainter::Antialiasing);
+ painter->drawPath(path);
+}
+
+
+void ArthurStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+
+ Q_ASSERT(option);
+ switch (element) {
+ case PE_FrameFocusRect:
+ break;
+
+ case PE_IndicatorRadioButton:
+ if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ bool hover = (button->state & State_Enabled) && (button->state & State_MouseOver);
+ painter->save();
+ QPixmap radio;
+ if (hover)
+ drawHoverRect(painter, widget->rect());
+
+ if (button->state & State_Sunken)
+ radio = cached(":res/images/radiobutton-on.png");
+ else if (button->state & State_On)
+ radio = cached(":res/images/radiobutton_on.png");
+ else
+ radio = cached(":res/images/radiobutton_off.png");
+ painter->drawPixmap(button->rect.topLeft(), radio);
+
+ painter->restore();
+ }
+ break;
+
+ case PE_PanelButtonCommand:
+ if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ bool hover = (button->state & State_Enabled) && (button->state & State_MouseOver);
+
+ painter->save();
+ const QPushButton *pushButton = qobject_cast<const QPushButton *>(widget);
+ Q_ASSERT(pushButton);
+ QWidget *parent = pushButton->parentWidget();
+ if (parent && qobject_cast<QGroupBox *>(parent)) {
+ QLinearGradient lg(0, 0, 0, parent->height());
+ lg.setColorAt(0, QColor(224,224,224));
+ lg.setColorAt(1, QColor(255,255,255));
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(lg);
+ painter->setBrushOrigin(-widget->mapToParent(QPoint(0,0)));
+ painter->drawRect(button->rect);
+ painter->setBrushOrigin(0,0);
+ }
+
+ bool down = (button->state & State_Sunken) || (button->state & State_On);
+
+ QPixmap left, right, mid;
+ if (down) {
+ left = cached(":res/images/button_pressed_cap_left.png");
+ right = cached(":res/images/button_pressed_cap_right.png");
+ mid = cached(":res/images/button_pressed_stretch.png");
+ } else {
+ left = cached(":res/images/button_normal_cap_left.png");
+ right = cached(":res/images/button_normal_cap_right.png");
+ mid = cached(":res/images/button_normal_stretch.png");
+ }
+ painter->drawPixmap(button->rect.topLeft(), left);
+ painter->drawTiledPixmap(QRect(button->rect.x() + left.width(),
+ button->rect.y(),
+ button->rect.width() - left.width() - right.width(),
+ left.height()),
+ mid);
+ painter->drawPixmap(button->rect.x() + button->rect.width() - right.width(),
+ button->rect.y(),
+ right);
+ if (hover)
+ painter->fillRect(widget->rect().adjusted(3,5,-3,-5), QColor(31,127,31,63));
+ painter->restore();
+ }
+ break;
+
+ case PE_FrameGroupBox:
+ if (const QStyleOptionFrameV2 *group
+ = qstyleoption_cast<const QStyleOptionFrameV2 *>(option)) {
+ const QRect &r = group->rect;
+
+ painter->save();
+ int radius = 14;
+ int radius2 = radius*2;
+ QPainterPath clipPath;
+ clipPath.moveTo(radius, 0);
+ clipPath.arcTo(r.right() - radius2, 0, radius2, radius2, 90, -90);
+ clipPath.arcTo(r.right() - radius2, r.bottom() - radius2, radius2, radius2, 0, -90);
+ clipPath.arcTo(r.left(), r.bottom() - radius2, radius2, radius2, 270, -90);
+ clipPath.arcTo(r.left(), r.top(), radius2, radius2, 180, -90);
+ painter->setClipPath(clipPath);
+ QPixmap titleStretch = cached(":res/images/title_stretch.png");
+ QPixmap topLeft = cached(":res/images/groupframe_topleft.png");
+ QPixmap topRight = cached(":res/images/groupframe_topright.png");
+ QPixmap bottomLeft = cached(":res/images/groupframe_bottom_left.png");
+ QPixmap bottomRight = cached(":res/images/groupframe_bottom_right.png");
+ QPixmap leftStretch = cached(":res/images/groupframe_left_stretch.png");
+ QPixmap topStretch = cached(":res/images/groupframe_top_stretch.png");
+ QPixmap rightStretch = cached(":res/images/groupframe_right_stretch.png");
+ QPixmap bottomStretch = cached(":res/images/groupframe_bottom_stretch.png");
+ QLinearGradient lg(0, 0, 0, r.height());
+ lg.setColorAt(0, QColor(224,224,224));
+ lg.setColorAt(1, QColor(255,255,255));
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(lg);
+ painter->drawRect(r.adjusted(0, titleStretch.height()/2, 0, 0));
+ painter->setClipping(false);
+
+ int topFrameOffset = titleStretch.height()/2 - 2;
+ painter->drawPixmap(r.topLeft() + QPoint(0, topFrameOffset), topLeft);
+ painter->drawPixmap(r.topRight() - QPoint(topRight.width()-1, 0)
+ + QPoint(0, topFrameOffset), topRight);
+ painter->drawPixmap(r.bottomLeft() - QPoint(0, bottomLeft.height()-1), bottomLeft);
+ painter->drawPixmap(r.bottomRight() - QPoint(bottomRight.width()-1,
+ bottomRight.height()-1), bottomRight);
+
+ QRect left = r;
+ left.setY(r.y() + topLeft.height() + topFrameOffset);
+ left.setWidth(leftStretch.width());
+ left.setHeight(r.height() - topLeft.height() - bottomLeft.height() - topFrameOffset);
+ painter->drawTiledPixmap(left, leftStretch);
+
+ QRect top = r;
+ top.setX(r.x() + topLeft.width());
+ top.setY(r.y() + topFrameOffset);
+ top.setWidth(r.width() - topLeft.width() - topRight.width());
+ top.setHeight(topLeft.height());
+ painter->drawTiledPixmap(top, topStretch);
+
+ QRect right = r;
+ right.setX(r.right() - rightStretch.width()+1);
+ right.setY(r.y() + topRight.height() + topFrameOffset);
+ right.setWidth(rightStretch.width());
+ right.setHeight(r.height() - topRight.height()
+ - bottomRight.height() - topFrameOffset);
+ painter->drawTiledPixmap(right, rightStretch);
+
+ QRect bottom = r;
+ bottom.setX(r.x() + bottomLeft.width());
+ bottom.setY(r.bottom() - bottomStretch.height()+1);
+ bottom.setWidth(r.width() - bottomLeft.width() - bottomRight.width());
+ bottom.setHeight(bottomLeft.height());
+ painter->drawTiledPixmap(bottom, bottomStretch);
+ painter->restore();
+ }
+ break;
+
+ default:
+ QWindowsStyle::drawPrimitive(element, option, painter, widget);
+ break;
+ }
+ return;
+}
+
+
+void ArthurStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ switch (control) {
+ case CC_Slider:
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QRect groove = subControlRect(CC_Slider, option, SC_SliderGroove, widget);
+ QRect handle = subControlRect(CC_Slider, option, SC_SliderHandle, widget);
+
+ painter->save();
+
+ bool hover = (slider->state & State_Enabled) && (slider->state & State_MouseOver);
+ if (hover) {
+ QRect moderated = widget->rect().adjusted(0, 4, 0, -4);
+ drawHoverRect(painter, moderated);
+ }
+
+ if ((option->subControls & SC_SliderGroove) && groove.isValid()) {
+ QPixmap grv = cached(":res/images/slider_bar.png");
+ painter->drawPixmap(QRect(groove.x() + 5, groove.y(),
+ groove.width() - 10, grv.height()),
+ grv);
+ }
+ if ((option->subControls & SC_SliderHandle) && handle.isValid()) {
+ QPixmap hndl = cached(":res/images/slider_thumb_on.png");
+ painter->drawPixmap(handle.topLeft(), hndl);
+ }
+
+ painter->restore();
+ }
+ break;
+ case CC_GroupBox:
+ if (const QStyleOptionGroupBox *groupBox
+ = qstyleoption_cast<const QStyleOptionGroupBox *>(option)) {
+ QStyleOptionGroupBox groupBoxCopy(*groupBox);
+ groupBoxCopy.subControls &= ~SC_GroupBoxLabel;
+ QWindowsStyle::drawComplexControl(control, &groupBoxCopy, painter, widget);
+
+ if (groupBox->subControls & SC_GroupBoxLabel) {
+ const QRect &r = groupBox->rect;
+ QPixmap titleLeft = cached(":res/images/title_cap_left.png");
+ QPixmap titleRight = cached(":res/images/title_cap_right.png");
+ QPixmap titleStretch = cached(":res/images/title_stretch.png");
+ int txt_width = groupBox->fontMetrics.width(groupBox->text) + 20;
+ painter->drawPixmap(r.center().x() - txt_width/2, 0, titleLeft);
+ QRect tileRect = subControlRect(control, groupBox, SC_GroupBoxLabel, widget);
+ painter->drawTiledPixmap(tileRect, titleStretch);
+ painter->drawPixmap(tileRect.x() + tileRect.width(), 0, titleRight);
+ int opacity = 31;
+ painter->setPen(QColor(0, 0, 0, opacity));
+ painter->drawText(tileRect.translated(0, 1),
+ Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text);
+ painter->drawText(tileRect.translated(2, 1),
+ Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text);
+ painter->setPen(QColor(0, 0, 0, opacity * 2));
+ painter->drawText(tileRect.translated(1, 1),
+ Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text);
+ painter->setPen(Qt::white);
+ painter->drawText(tileRect, Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text);
+ }
+ }
+ break;
+ default:
+ QWindowsStyle::drawComplexControl(control, option, painter, widget);
+ break;
+ }
+ return;
+}
+
+QRect ArthurStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
+ SubControl subControl, const QWidget *widget) const
+{
+ QRect rect;
+
+ switch (control) {
+ default:
+ rect = QWindowsStyle::subControlRect(control, option, subControl, widget);
+ break;
+ case CC_GroupBox:
+ if (const QStyleOptionGroupBox *group
+ = qstyleoption_cast<const QStyleOptionGroupBox *>(option)) {
+ switch (subControl) {
+ default:
+ rect = QWindowsStyle::subControlRect(control, option, subControl, widget);
+ break;
+ case SC_GroupBoxContents:
+ rect = QWindowsStyle::subControlRect(control, option, subControl, widget);
+ rect.adjust(0, -8, 0, 0);
+ break;
+ case SC_GroupBoxFrame:
+ rect = group->rect;
+ break;
+ case SC_GroupBoxLabel:
+ QPixmap titleLeft = cached(":res/images/title_cap_left.png");
+ QPixmap titleRight = cached(":res/images/title_cap_right.png");
+ QPixmap titleStretch = cached(":res/images/title_stretch.png");
+ int txt_width = group->fontMetrics.width(group->text) + 20;
+ rect = QRect(group->rect.center().x() - txt_width/2 + titleLeft.width(), 0,
+ txt_width - titleLeft.width() - titleRight.width(),
+ titleStretch.height());
+ break;
+ }
+ }
+ break;
+ }
+
+ if (control == CC_Slider && subControl == SC_SliderHandle) {
+ rect.setWidth(13);
+ rect.setHeight(27);
+ } else if (control == CC_Slider && subControl == SC_SliderGroove) {
+ rect.setHeight(9);
+ rect.moveTop(27/2 - 9/2);
+ }
+ return rect;
+}
+
+QSize ArthurStyle::sizeFromContents(ContentsType type, const QStyleOption *option,
+ const QSize &size, const QWidget *widget) const
+{
+ QSize newSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
+
+
+ switch (type) {
+ case CT_RadioButton:
+ newSize += QSize(20, 0);
+ break;
+
+ case CT_PushButton:
+ newSize.setHeight(26);
+ break;
+
+ case CT_Slider:
+ newSize.setHeight(27);
+ break;
+
+ default:
+ break;
+ }
+
+ return newSize;
+}
+
+int ArthurStyle::pixelMetric(PixelMetric pm, const QStyleOption *opt, const QWidget *widget) const
+{
+ if (pm == PM_SliderLength)
+ return 13;
+ return QWindowsStyle::pixelMetric(pm, opt, widget);
+}
+
+void ArthurStyle::polish(QWidget *widget)
+{
+ if (widget->layout() && qobject_cast<QGroupBox *>(widget)) {
+ if (qFindChildren<QGroupBox *>(widget).size() == 0) {
+ widget->layout()->setSpacing(0);
+ widget->layout()->setMargin(12);
+ } else {
+ widget->layout()->setMargin(13);
+ }
+ }
+
+ if (qobject_cast<QPushButton *>(widget)
+ || qobject_cast<QRadioButton *>(widget)
+ || qobject_cast<QSlider *>(widget)) {
+ widget->setAttribute(Qt::WA_Hover);
+ }
+
+ QPalette pal = widget->palette();
+ if (widget->isWindow()) {
+ pal.setColor(QPalette::Background, QColor(241, 241, 241));
+ widget->setPalette(pal);
+ }
+
+}
+
+void ArthurStyle::unpolish(QWidget *widget)
+{
+ if (qobject_cast<QPushButton *>(widget)
+ || qobject_cast<QRadioButton *>(widget)
+ || qobject_cast<QSlider *>(widget)) {
+ widget->setAttribute(Qt::WA_Hover, false);
+ }
+}
+
+void ArthurStyle::polish(QPalette &palette)
+{
+ palette.setColor(QPalette::Background, QColor(241, 241, 241));
+}
+
+QRect ArthurStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
+{
+ QRect r;
+ switch(element) {
+ case SE_RadioButtonClickRect:
+ r = widget->rect();
+ break;
+ case SE_RadioButtonContents:
+ r = widget->rect().adjusted(20, 0, 0, 0);
+ break;
+ default:
+ r = QWindowsStyle::subElementRect(element, option, widget);
+ break;
+ }
+
+ if (qobject_cast<const QRadioButton*>(widget))
+ r = r.adjusted(5, 0, -5, 0);
+
+ return r;
+}
diff --git a/demos/shared/arthurstyle.h b/demos/shared/arthurstyle.h
new file mode 100644
index 0000000..ec79361
--- /dev/null
+++ b/demos/shared/arthurstyle.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ARTHURSTYLE_H
+#define ARTHURSTYLE_H
+
+#include <QWindowsStyle>
+
+QT_USE_NAMESPACE
+
+class ArthurStyle : public QWindowsStyle
+{
+public:
+ ArthurStyle();
+
+ void drawHoverRect(QPainter *painter, const QRect &rect) const;
+
+ void drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget = 0) const;
+// void drawControl(ControlElement element, const QStyleOption *option,
+// QPainter *painter, const QWidget *widget) const;
+ void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const;
+ QSize sizeFromContents(ContentsType type, const QStyleOption *option,
+ const QSize &size, const QWidget *widget) const;
+
+ QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const;
+ QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt,
+ SubControl sc, const QWidget *widget) const;
+
+// SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+// const QPoint &pos, const QWidget *widget = 0) const;
+
+ int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const;
+
+ void polish(QPalette &palette);
+ void polish(QWidget *widget);
+ void unpolish(QWidget *widget);
+};
+
+#endif
diff --git a/demos/shared/arthurwidgets.cpp b/demos/shared/arthurwidgets.cpp
new file mode 100644
index 0000000..f9eed99
--- /dev/null
+++ b/demos/shared/arthurwidgets.cpp
@@ -0,0 +1,371 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "arthurwidgets.h"
+#include <QApplication>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPixmapCache>
+#include <QtEvents>
+#include <QTextDocument>
+#include <QAbstractTextDocumentLayout>
+#include <QFile>
+#include <QTextBrowser>
+#include <QBoxLayout>
+
+#include <private/qpixmapdata_p.h>
+
+extern QPixmap cached(const QString &img);
+
+ArthurFrame::ArthurFrame(QWidget *parent)
+ : QWidget(parent)
+ , m_prefer_image(false)
+{
+#ifdef QT_OPENGL_SUPPORT
+ glw = 0;
+ m_use_opengl = false;
+ QGLFormat f = QGLFormat::defaultFormat();
+ f.setSampleBuffers(true);
+ f.setStencil(true);
+ f.setAlpha(true);
+ f.setAlphaBufferSize(8);
+ QGLFormat::setDefaultFormat(f);
+#endif
+ m_document = 0;
+ m_show_doc = false;
+
+ m_tile = QPixmap(128, 128);
+ m_tile.fill(Qt::white);
+ QPainter pt(&m_tile);
+ QColor color(230, 230, 230);
+ pt.fillRect(0, 0, 64, 64, color);
+ pt.fillRect(64, 64, 64, 64, color);
+ pt.end();
+
+// QPalette pal = palette();
+// pal.setBrush(backgroundRole(), m_tile);
+// setPalette(pal);
+
+#ifdef Q_WS_X11
+ QPixmap xRenderPixmap(1, 1);
+ m_prefer_image = xRenderPixmap.pixmapData()->classId() == QPixmapData::X11Class && !xRenderPixmap.x11PictureHandle();
+#endif
+}
+
+
+#ifdef QT_OPENGL_SUPPORT
+void ArthurFrame::enableOpenGL(bool use_opengl)
+{
+ m_use_opengl = use_opengl;
+
+ if (!glw) {
+ glw = new GLWidget(this);
+ glw->setAutoFillBackground(false);
+ glw->disableAutoBufferSwap();
+ QApplication::postEvent(this, new QResizeEvent(size(), size()));
+ }
+
+ if (use_opengl) {
+ glw->show();
+ } else {
+ glw->hide();
+ }
+
+ update();
+}
+#endif
+
+void ArthurFrame::paintEvent(QPaintEvent *e)
+{
+#ifdef Q_WS_QWS
+ static QPixmap *static_image = 0;
+#else
+ static QImage *static_image = 0;
+#endif
+ QPainter painter;
+ if (preferImage()
+#ifdef QT_OPENGL_SUPPORT
+ && !m_use_opengl
+#endif
+ ) {
+ if (!static_image || static_image->size() != size()) {
+ delete static_image;
+#ifdef Q_WS_QWS
+ static_image = new QPixmap(size());
+#else
+ static_image = new QImage(size(), QImage::Format_RGB32);
+#endif
+ }
+ painter.begin(static_image);
+
+ int o = 10;
+
+ QBrush bg = palette().brush(QPalette::Background);
+ painter.fillRect(0, 0, o, o, bg);
+ painter.fillRect(width() - o, 0, o, o, bg);
+ painter.fillRect(0, height() - o, o, o, bg);
+ painter.fillRect(width() - o, height() - o, o, o, bg);
+ } else {
+#ifdef QT_OPENGL_SUPPORT
+ if (m_use_opengl) {
+ painter.begin(glw);
+ painter.fillRect(QRectF(0, 0, glw->width(), glw->height()), palette().color(backgroundRole()));
+ } else {
+ painter.begin(this);
+ }
+#else
+ painter.begin(this);
+#endif
+ }
+
+ painter.setClipRect(e->rect());
+
+ painter.setRenderHint(QPainter::Antialiasing);
+
+ QPainterPath clipPath;
+
+ QRect r = rect();
+ qreal left = r.x() + 1;
+ qreal top = r.y() + 1;
+ qreal right = r.right();
+ qreal bottom = r.bottom();
+ qreal radius2 = 8 * 2;
+
+ clipPath.moveTo(right - radius2, top);
+ clipPath.arcTo(right - radius2, top, radius2, radius2, 90, -90);
+ clipPath.arcTo(right - radius2, bottom - radius2, radius2, radius2, 0, -90);
+ clipPath.arcTo(left, bottom - radius2, radius2, radius2, 270, -90);
+ clipPath.arcTo(left, top, radius2, radius2, 180, -90);
+ clipPath.closeSubpath();
+
+ painter.save();
+ painter.setClipPath(clipPath, Qt::IntersectClip);
+
+ painter.drawTiledPixmap(rect(), m_tile);
+
+ // client painting
+
+ paint(&painter);
+
+ painter.restore();
+
+ painter.save();
+ if (m_show_doc)
+ paintDescription(&painter);
+ painter.restore();
+
+ int level = 180;
+ painter.setPen(QPen(QColor(level, level, level), 2));
+ painter.setBrush(Qt::NoBrush);
+ painter.drawPath(clipPath);
+
+ if (preferImage()
+#ifdef QT_OPENGL_SUPPORT
+ && !m_use_opengl
+#endif
+ ) {
+ painter.end();
+ painter.begin(this);
+#ifdef Q_WS_QWS
+ painter.drawPixmap(e->rect(), *static_image, e->rect());
+#else
+ painter.drawImage(e->rect(), *static_image, e->rect());
+#endif
+ }
+
+#ifdef QT_OPENGL_SUPPORT
+ if (m_use_opengl && (inherits("PathDeformRenderer") || inherits("PathStrokeRenderer") || inherits("CompositionRenderer") || m_show_doc))
+ glw->swapBuffers();
+#endif
+}
+
+void ArthurFrame::resizeEvent(QResizeEvent *e)
+{
+#ifdef QT_OPENGL_SUPPORT
+ if (glw)
+ glw->setGeometry(0, 0, e->size().width()-1, e->size().height()-1);
+#endif
+ QWidget::resizeEvent(e);
+}
+
+void ArthurFrame::setDescriptionEnabled(bool enabled)
+{
+ if (m_show_doc != enabled) {
+ m_show_doc = enabled;
+ emit descriptionEnabledChanged(m_show_doc);
+ update();
+ }
+}
+
+void ArthurFrame::loadDescription(const QString &fileName)
+{
+ QFile textFile(fileName);
+ QString text;
+ if (!textFile.open(QFile::ReadOnly))
+ text = QString("Unable to load resource file: '%1'").arg(fileName);
+ else
+ text = textFile.readAll();
+ setDescription(text);
+}
+
+
+void ArthurFrame::setDescription(const QString &text)
+{
+ m_document = new QTextDocument(this);
+ m_document->setHtml(text);
+}
+
+void ArthurFrame::paintDescription(QPainter *painter)
+{
+ if (!m_document)
+ return;
+
+ int pageWidth = qMax(width() - 100, 100);
+ int pageHeight = qMax(height() - 100, 100);
+ if (pageWidth != m_document->pageSize().width()) {
+ m_document->setPageSize(QSize(pageWidth, pageHeight));
+ }
+
+ QRect textRect(width() / 2 - pageWidth / 2,
+ height() / 2 - pageHeight / 2,
+ pageWidth,
+ pageHeight);
+ int pad = 10;
+ QRect clearRect = textRect.adjusted(-pad, -pad, pad, pad);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(QColor(0, 0, 0, 63));
+ int shade = 10;
+ painter->drawRect(clearRect.x() + clearRect.width() + 1,
+ clearRect.y() + shade,
+ shade,
+ clearRect.height() + 1);
+ painter->drawRect(clearRect.x() + shade,
+ clearRect.y() + clearRect.height() + 1,
+ clearRect.width() - shade + 1,
+ shade);
+
+ painter->setRenderHint(QPainter::Antialiasing, false);
+ painter->setBrush(QColor(255, 255, 255, 220));
+ painter->setPen(Qt::black);
+ painter->drawRect(clearRect);
+
+ painter->setClipRegion(textRect, Qt::IntersectClip);
+ painter->translate(textRect.topLeft());
+
+ QAbstractTextDocumentLayout::PaintContext ctx;
+
+ QLinearGradient g(0, 0, 0, textRect.height());
+ g.setColorAt(0, Qt::black);
+ g.setColorAt(0.9, Qt::black);
+ g.setColorAt(1, Qt::transparent);
+
+ QPalette pal = palette();
+ pal.setBrush(QPalette::Text, g);
+
+ ctx.palette = pal;
+ ctx.clip = QRect(0, 0, textRect.width(), textRect.height());
+ m_document->documentLayout()->draw(painter, ctx);
+}
+
+void ArthurFrame::loadSourceFile(const QString &sourceFile)
+{
+ m_sourceFileName = sourceFile;
+}
+
+void ArthurFrame::showSource()
+{
+ // Check for existing source
+ if (qFindChild<QTextBrowser *>(this))
+ return;
+
+ QString contents;
+ if (m_sourceFileName.isEmpty()) {
+ contents = QString("No source for widget: '%1'").arg(objectName());
+ } else {
+ QFile f(m_sourceFileName);
+ if (!f.open(QFile::ReadOnly))
+ contents = QString("Could not open file: '%1'").arg(m_sourceFileName);
+ else
+ contents = f.readAll();
+ }
+
+ contents.replace('&', "&amp;");
+ contents.replace('<', "&lt;");
+ contents.replace('>', "&gt;");
+
+ QStringList keywords;
+ keywords << "for " << "if " << "switch " << " int " << "#include " << "const"
+ << "void " << "uint " << "case " << "double " << "#define " << "static"
+ << "new" << "this";
+
+ foreach (QString keyword, keywords)
+ contents.replace(keyword, QLatin1String("<font color=olive>") + keyword + QLatin1String("</font>"));
+ contents.replace("(int ", "(<font color=olive><b>int </b></font>");
+
+ QStringList ppKeywords;
+ ppKeywords << "#ifdef" << "#ifndef" << "#if" << "#endif" << "#else";
+
+ foreach (QString keyword, ppKeywords)
+ contents.replace(keyword, QLatin1String("<font color=navy>") + keyword + QLatin1String("</font>"));
+
+ contents.replace(QRegExp("(\\d\\d?)"), QLatin1String("<font color=navy>\\1</font>"));
+
+ QRegExp commentRe("(//.+)\\n");
+ commentRe.setMinimal(true);
+ contents.replace(commentRe, QLatin1String("<font color=red>\\1</font>\n"));
+
+ QRegExp stringLiteralRe("(\".+\")");
+ stringLiteralRe.setMinimal(true);
+ contents.replace(stringLiteralRe, QLatin1String("<font color=green>\\1</font>"));
+
+ QString html = contents;
+ html.prepend("<html><pre>");
+ html.append("</pre></html>");
+
+ QTextBrowser *sourceViewer = new QTextBrowser(0);
+ sourceViewer->setWindowTitle("Source: " + m_sourceFileName.mid(5));
+ sourceViewer->setParent(this, Qt::Dialog);
+ sourceViewer->setAttribute(Qt::WA_DeleteOnClose);
+ sourceViewer->setLineWrapMode(QTextEdit::NoWrap);
+ sourceViewer->setHtml(html);
+ sourceViewer->resize(600, 600);
+ sourceViewer->show();
+}
diff --git a/demos/shared/arthurwidgets.h b/demos/shared/arthurwidgets.h
new file mode 100644
index 0000000..4d55b61
--- /dev/null
+++ b/demos/shared/arthurwidgets.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ARTHURWIDGETS_H
+#define ARTHURWIDGETS_H
+
+#include "arthurstyle.h"
+#include <QBitmap>
+#include <QPushButton>
+#include <QGroupBox>
+
+#if defined(QT_OPENGL_SUPPORT)
+#include <QGLWidget>
+class GLWidget : public QGLWidget
+{
+public:
+ GLWidget(QWidget *parent)
+ : QGLWidget(QGLFormat(QGL::SampleBuffers), parent) {}
+ void disableAutoBufferSwap() { setAutoBufferSwap(false); }
+ void paintEvent(QPaintEvent *) { parentWidget()->update(); }
+};
+#endif
+
+QT_FORWARD_DECLARE_CLASS(QTextDocument)
+QT_FORWARD_DECLARE_CLASS(QTextEdit)
+QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
+
+class ArthurFrame : public QWidget
+{
+ Q_OBJECT
+public:
+ ArthurFrame(QWidget *parent);
+ virtual void paint(QPainter *) {}
+
+
+ void paintDescription(QPainter *p);
+
+ void loadDescription(const QString &filename);
+ void setDescription(const QString &htmlDesc);
+
+ void loadSourceFile(const QString &fileName);
+
+ bool preferImage() const { return m_prefer_image; }
+
+#if defined(QT_OPENGL_SUPPORT)
+ QGLWidget *glWidget() const { return glw; }
+#endif
+
+public slots:
+ void setPreferImage(bool pi) { m_prefer_image = pi; }
+ void setDescriptionEnabled(bool enabled);
+ void showSource();
+
+#if defined(QT_OPENGL_SUPPORT)
+ void enableOpenGL(bool use_opengl);
+ bool usesOpenGL() { return m_use_opengl; }
+#endif
+
+signals:
+ void descriptionEnabledChanged(bool);
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void resizeEvent(QResizeEvent *);
+
+#if defined(QT_OPENGL_SUPPORT)
+ GLWidget *glw;
+ bool m_use_opengl;
+#endif
+ QPixmap m_tile;
+
+ bool m_show_doc;
+ bool m_prefer_image;
+ QTextDocument *m_document;
+
+ QString m_sourceFileName;
+
+};
+
+#endif
diff --git a/demos/shared/hoverpoints.cpp b/demos/shared/hoverpoints.cpp
new file mode 100644
index 0000000..70062f6
--- /dev/null
+++ b/demos/shared/hoverpoints.cpp
@@ -0,0 +1,333 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifdef QT_OPENGL_SUPPORT
+#include <QGLWidget>
+#endif
+
+#include "arthurwidgets.h"
+#include "hoverpoints.h"
+
+#define printf
+
+HoverPoints::HoverPoints(QWidget *widget, PointShape shape)
+ : QObject(widget)
+{
+ m_widget = widget;
+ widget->installEventFilter(this);
+
+ m_connectionType = CurveConnection;
+ m_sortType = NoSort;
+ m_shape = shape;
+ m_pointPen = QPen(QColor(255, 255, 255, 191), 1);
+ m_connectionPen = QPen(QColor(255, 255, 255, 127), 2);
+ m_pointBrush = QBrush(QColor(191, 191, 191, 127));
+ m_pointSize = QSize(11, 11);
+ m_currentIndex = -1;
+ m_editable = true;
+ m_enabled = true;
+
+ connect(this, SIGNAL(pointsChanged(const QPolygonF &)),
+ m_widget, SLOT(update()));
+}
+
+
+void HoverPoints::setEnabled(bool enabled)
+{
+ if (m_enabled != enabled) {
+ m_enabled = enabled;
+ m_widget->update();
+ }
+}
+
+
+bool HoverPoints::eventFilter(QObject *object, QEvent *event)
+{
+ if (object == m_widget && m_enabled) {
+ switch (event->type()) {
+
+ case QEvent::MouseButtonPress:
+ {
+ QMouseEvent *me = (QMouseEvent *) event;
+
+ QPointF clickPos = me->pos();
+ int index = -1;
+ for (int i=0; i<m_points.size(); ++i) {
+ QPainterPath path;
+ if (m_shape == CircleShape)
+ path.addEllipse(pointBoundingRect(i));
+ else
+ path.addRect(pointBoundingRect(i));
+
+ if (path.contains(clickPos)) {
+ index = i;
+ break;
+ }
+ }
+
+ if (me->button() == Qt::LeftButton) {
+ if (index == -1) {
+ if (!m_editable)
+ return false;
+ int pos = 0;
+ // Insert sort for x or y
+ if (m_sortType == XSort) {
+ for (int i=0; i<m_points.size(); ++i)
+ if (m_points.at(i).x() > clickPos.x()) {
+ pos = i;
+ break;
+ }
+ } else if (m_sortType == YSort) {
+ for (int i=0; i<m_points.size(); ++i)
+ if (m_points.at(i).y() > clickPos.y()) {
+ pos = i;
+ break;
+ }
+ }
+
+ m_points.insert(pos, clickPos);
+ m_locks.insert(pos, 0);
+ m_currentIndex = pos;
+ firePointChange();
+ } else {
+ m_currentIndex = index;
+ }
+ return true;
+
+ } else if (me->button() == Qt::RightButton) {
+ if (index >= 0 && m_editable) {
+ if (m_locks[index] == 0) {
+ m_locks.remove(index);
+ m_points.remove(index);
+ }
+ firePointChange();
+ return true;
+ }
+ }
+
+ }
+ break;
+
+ case QEvent::MouseButtonRelease:
+ m_currentIndex = -1;
+ break;
+
+ case QEvent::MouseMove:
+ if (m_currentIndex >= 0)
+ movePoint(m_currentIndex, ((QMouseEvent *)event)->pos());
+ break;
+
+ case QEvent::Resize:
+ {
+ QResizeEvent *e = (QResizeEvent *) event;
+ if (e->oldSize().width() == 0 || e->oldSize().height() == 0)
+ break;
+ qreal stretch_x = e->size().width() / qreal(e->oldSize().width());
+ qreal stretch_y = e->size().height() / qreal(e->oldSize().height());
+ for (int i=0; i<m_points.size(); ++i) {
+ QPointF p = m_points[i];
+ movePoint(i, QPointF(p.x() * stretch_x, p.y() * stretch_y), false);
+ }
+
+ firePointChange();
+ break;
+ }
+
+ case QEvent::Paint:
+ {
+ QWidget *that_widget = m_widget;
+ m_widget = 0;
+ QApplication::sendEvent(object, event);
+ m_widget = that_widget;
+ paintPoints();
+#ifdef QT_OPENGL_SUPPORT
+ ArthurFrame *af = qobject_cast<ArthurFrame *>(that_widget);
+ if (af && af->usesOpenGL())
+ af->glWidget()->swapBuffers();
+#endif
+ return true;
+ }
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
+
+void HoverPoints::paintPoints()
+{
+ QPainter p;
+#ifdef QT_OPENGL_SUPPORT
+ ArthurFrame *af = qobject_cast<ArthurFrame *>(m_widget);
+ if (af && af->usesOpenGL())
+ p.begin(af->glWidget());
+ else
+ p.begin(m_widget);
+#else
+ p.begin(m_widget);
+#endif
+
+ p.setRenderHint(QPainter::Antialiasing);
+
+ if (m_connectionPen.style() != Qt::NoPen && m_connectionType != NoConnection) {
+ p.setPen(m_connectionPen);
+
+ if (m_connectionType == CurveConnection) {
+ QPainterPath path;
+ path.moveTo(m_points.at(0));
+ for (int i=1; i<m_points.size(); ++i) {
+ QPointF p1 = m_points.at(i-1);
+ QPointF p2 = m_points.at(i);
+ qreal distance = p2.x() - p1.x();
+
+ path.cubicTo(p1.x() + distance / 2, p1.y(),
+ p1.x() + distance / 2, p2.y(),
+ p2.x(), p2.y());
+ }
+ p.drawPath(path);
+ } else {
+ p.drawPolyline(m_points);
+ }
+ }
+
+ p.setPen(m_pointPen);
+ p.setBrush(m_pointBrush);
+
+ for (int i=0; i<m_points.size(); ++i) {
+ QRectF bounds = pointBoundingRect(i);
+ if (m_shape == CircleShape)
+ p.drawEllipse(bounds);
+ else
+ p.drawRect(bounds);
+ }
+}
+
+static QPointF bound_point(const QPointF &point, const QRectF &bounds, int lock)
+{
+ QPointF p = point;
+
+ qreal left = bounds.left();
+ qreal right = bounds.right();
+ qreal top = bounds.top();
+ qreal bottom = bounds.bottom();
+
+ if (p.x() < left || (lock & HoverPoints::LockToLeft)) p.setX(left);
+ else if (p.x() > right || (lock & HoverPoints::LockToRight)) p.setX(right);
+
+ if (p.y() < top || (lock & HoverPoints::LockToTop)) p.setY(top);
+ else if (p.y() > bottom || (lock & HoverPoints::LockToBottom)) p.setY(bottom);
+
+ return p;
+}
+
+void HoverPoints::setPoints(const QPolygonF &points)
+{
+ m_points.clear();
+ for (int i=0; i<points.size(); ++i)
+ m_points << bound_point(points.at(i), boundingRect(), 0);
+
+ m_locks.clear();
+ if (m_points.size() > 0) {
+ m_locks.resize(m_points.size());
+
+ m_locks.fill(0);
+ }
+}
+
+
+void HoverPoints::movePoint(int index, const QPointF &point, bool emitUpdate)
+{
+ m_points[index] = bound_point(point, boundingRect(), m_locks.at(index));
+ if (emitUpdate)
+ firePointChange();
+}
+
+
+inline static bool x_less_than(const QPointF &p1, const QPointF &p2)
+{
+ return p1.x() < p2.x();
+}
+
+
+inline static bool y_less_than(const QPointF &p1, const QPointF &p2)
+{
+ return p1.y() < p2.y();
+}
+
+void HoverPoints::firePointChange()
+{
+// printf("HoverPoints::firePointChange(), current=%d\n", m_currentIndex);
+
+ if (m_sortType != NoSort) {
+
+ QPointF oldCurrent;
+ if (m_currentIndex != -1) {
+ oldCurrent = m_points[m_currentIndex];
+ }
+
+ if (m_sortType == XSort)
+ qSort(m_points.begin(), m_points.end(), x_less_than);
+ else if (m_sortType == YSort)
+ qSort(m_points.begin(), m_points.end(), y_less_than);
+
+ // Compensate for changed order...
+ if (m_currentIndex != -1) {
+ for (int i=0; i<m_points.size(); ++i) {
+ if (m_points[i] == oldCurrent) {
+ m_currentIndex = i;
+ break;
+ }
+ }
+ }
+
+// printf(" - firePointChange(), current=%d\n", m_currentIndex);
+
+ }
+
+// for (int i=0; i<m_points.size(); ++i) {
+// printf(" - point(%2d)=[%.2f, %.2f], lock=%d\n",
+// i, m_points.at(i).x(), m_points.at(i).y(), m_locks.at(i));
+// }
+
+ emit pointsChanged(m_points);
+}
diff --git a/demos/shared/hoverpoints.h b/demos/shared/hoverpoints.h
new file mode 100644
index 0000000..cf8742d
--- /dev/null
+++ b/demos/shared/hoverpoints.h
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HOVERPOINTS_H
+#define HOVERPOINTS_H
+
+#include <QtGui>
+
+QT_FORWARD_DECLARE_CLASS(QBypassWidget)
+
+class HoverPoints : public QObject
+{
+ Q_OBJECT
+public:
+ enum PointShape {
+ CircleShape,
+ RectangleShape
+ };
+
+ enum LockType {
+ LockToLeft = 0x01,
+ LockToRight = 0x02,
+ LockToTop = 0x04,
+ LockToBottom = 0x08
+ };
+
+ enum SortType {
+ NoSort,
+ XSort,
+ YSort
+ };
+
+ enum ConnectionType {
+ NoConnection,
+ LineConnection,
+ CurveConnection
+ };
+
+ HoverPoints(QWidget *widget, PointShape shape);
+
+ bool eventFilter(QObject *object, QEvent *event);
+
+ void paintPoints();
+
+ inline QRectF boundingRect() const;
+ void setBoundingRect(const QRectF &boundingRect) { m_bounds = boundingRect; }
+
+ QPolygonF points() const { return m_points; }
+ void setPoints(const QPolygonF &points);
+
+ QSizeF pointSize() const { return m_pointSize; }
+ void setPointSize(const QSizeF &size) { m_pointSize = size; }
+
+ SortType sortType() const { return m_sortType; }
+ void setSortType(SortType sortType) { m_sortType = sortType; }
+
+ ConnectionType connectionType() const { return m_connectionType; }
+ void setConnectionType(ConnectionType connectionType) { m_connectionType = connectionType; }
+
+ void setConnectionPen(const QPen &pen) { m_connectionPen = pen; }
+ void setShapePen(const QPen &pen) { m_pointPen = pen; }
+ void setShapeBrush(const QBrush &brush) { m_pointBrush = brush; }
+
+ void setPointLock(int pos, LockType lock) { m_locks[pos] = lock; }
+
+ void setEditable(bool editable) { m_editable = editable; }
+ bool editable() const { return m_editable; }
+
+public slots:
+ void setEnabled(bool enabled);
+ void setDisabled(bool disabled) { setEnabled(!disabled); }
+
+signals:
+ void pointsChanged(const QPolygonF &points);
+
+public:
+ void firePointChange();
+
+private:
+ inline QRectF pointBoundingRect(int i) const;
+ void movePoint(int i, const QPointF &newPos, bool emitChange = true);
+
+ QWidget *m_widget;
+
+ QPolygonF m_points;
+ QRectF m_bounds;
+ PointShape m_shape;
+ SortType m_sortType;
+ ConnectionType m_connectionType;
+
+ QVector<uint> m_locks;
+
+ QSizeF m_pointSize;
+ int m_currentIndex;
+ bool m_editable;
+ bool m_enabled;
+
+ QPen m_pointPen;
+ QBrush m_pointBrush;
+ QPen m_connectionPen;
+};
+
+
+inline QRectF HoverPoints::pointBoundingRect(int i) const
+{
+ QPointF p = m_points.at(i);
+ qreal w = m_pointSize.width();
+ qreal h = m_pointSize.height();
+ qreal x = p.x() - w / 2;
+ qreal y = p.y() - h / 2;
+ return QRectF(x, y, w, h);
+}
+
+inline QRectF HoverPoints::boundingRect() const
+{
+ if (m_bounds.isEmpty())
+ return m_widget->rect();
+ else
+ return m_bounds;
+}
+
+#endif // HOVERPOINTS_H
diff --git a/demos/shared/images/bg_pattern.png b/demos/shared/images/bg_pattern.png
new file mode 100644
index 0000000..ee67026
--- /dev/null
+++ b/demos/shared/images/bg_pattern.png
Binary files differ
diff --git a/demos/shared/images/button_normal_cap_left.png b/demos/shared/images/button_normal_cap_left.png
new file mode 100644
index 0000000..db31dd9
--- /dev/null
+++ b/demos/shared/images/button_normal_cap_left.png
Binary files differ
diff --git a/demos/shared/images/button_normal_cap_right.png b/demos/shared/images/button_normal_cap_right.png
new file mode 100644
index 0000000..38ead1c
--- /dev/null
+++ b/demos/shared/images/button_normal_cap_right.png
Binary files differ
diff --git a/demos/shared/images/button_normal_stretch.png b/demos/shared/images/button_normal_stretch.png
new file mode 100644
index 0000000..87abe67
--- /dev/null
+++ b/demos/shared/images/button_normal_stretch.png
Binary files differ
diff --git a/demos/shared/images/button_pressed_cap_left.png b/demos/shared/images/button_pressed_cap_left.png
new file mode 100644
index 0000000..66bfc13
--- /dev/null
+++ b/demos/shared/images/button_pressed_cap_left.png
Binary files differ
diff --git a/demos/shared/images/button_pressed_cap_right.png b/demos/shared/images/button_pressed_cap_right.png
new file mode 100644
index 0000000..3d4cfe2
--- /dev/null
+++ b/demos/shared/images/button_pressed_cap_right.png
Binary files differ
diff --git a/demos/shared/images/button_pressed_stretch.png b/demos/shared/images/button_pressed_stretch.png
new file mode 100644
index 0000000..4dd4ad1
--- /dev/null
+++ b/demos/shared/images/button_pressed_stretch.png
Binary files differ
diff --git a/demos/shared/images/curve_thing_edit-6.png b/demos/shared/images/curve_thing_edit-6.png
new file mode 100644
index 0000000..034b474
--- /dev/null
+++ b/demos/shared/images/curve_thing_edit-6.png
Binary files differ
diff --git a/demos/shared/images/frame_bottom.png b/demos/shared/images/frame_bottom.png
new file mode 100644
index 0000000..889b40d
--- /dev/null
+++ b/demos/shared/images/frame_bottom.png
Binary files differ
diff --git a/demos/shared/images/frame_bottomleft.png b/demos/shared/images/frame_bottomleft.png
new file mode 100644
index 0000000..0b3023f
--- /dev/null
+++ b/demos/shared/images/frame_bottomleft.png
Binary files differ
diff --git a/demos/shared/images/frame_bottomright.png b/demos/shared/images/frame_bottomright.png
new file mode 100644
index 0000000..0021e35
--- /dev/null
+++ b/demos/shared/images/frame_bottomright.png
Binary files differ
diff --git a/demos/shared/images/frame_left.png b/demos/shared/images/frame_left.png
new file mode 100644
index 0000000..40f331c
--- /dev/null
+++ b/demos/shared/images/frame_left.png
Binary files differ
diff --git a/demos/shared/images/frame_right.png b/demos/shared/images/frame_right.png
new file mode 100644
index 0000000..023af8c
--- /dev/null
+++ b/demos/shared/images/frame_right.png
Binary files differ
diff --git a/demos/shared/images/frame_top.png b/demos/shared/images/frame_top.png
new file mode 100644
index 0000000..001f3a7
--- /dev/null
+++ b/demos/shared/images/frame_top.png
Binary files differ
diff --git a/demos/shared/images/frame_topleft.png b/demos/shared/images/frame_topleft.png
new file mode 100644
index 0000000..58c68d4
--- /dev/null
+++ b/demos/shared/images/frame_topleft.png
Binary files differ
diff --git a/demos/shared/images/frame_topright.png b/demos/shared/images/frame_topright.png
new file mode 100644
index 0000000..6a7e8d3
--- /dev/null
+++ b/demos/shared/images/frame_topright.png
Binary files differ
diff --git a/demos/shared/images/groupframe_bottom_left.png b/demos/shared/images/groupframe_bottom_left.png
new file mode 100644
index 0000000..af2fe06
--- /dev/null
+++ b/demos/shared/images/groupframe_bottom_left.png
Binary files differ
diff --git a/demos/shared/images/groupframe_bottom_right.png b/demos/shared/images/groupframe_bottom_right.png
new file mode 100644
index 0000000..fdf2e97
--- /dev/null
+++ b/demos/shared/images/groupframe_bottom_right.png
Binary files differ
diff --git a/demos/shared/images/groupframe_bottom_stretch.png b/demos/shared/images/groupframe_bottom_stretch.png
new file mode 100644
index 0000000..f47b67d
--- /dev/null
+++ b/demos/shared/images/groupframe_bottom_stretch.png
Binary files differ
diff --git a/demos/shared/images/groupframe_left_stretch.png b/demos/shared/images/groupframe_left_stretch.png
new file mode 100644
index 0000000..c122f46
--- /dev/null
+++ b/demos/shared/images/groupframe_left_stretch.png
Binary files differ
diff --git a/demos/shared/images/groupframe_right_stretch.png b/demos/shared/images/groupframe_right_stretch.png
new file mode 100644
index 0000000..1056b78
--- /dev/null
+++ b/demos/shared/images/groupframe_right_stretch.png
Binary files differ
diff --git a/demos/shared/images/groupframe_top_stretch.png b/demos/shared/images/groupframe_top_stretch.png
new file mode 100644
index 0000000..5746ef9
--- /dev/null
+++ b/demos/shared/images/groupframe_top_stretch.png
Binary files differ
diff --git a/demos/shared/images/groupframe_topleft.png b/demos/shared/images/groupframe_topleft.png
new file mode 100644
index 0000000..98d9cd9
--- /dev/null
+++ b/demos/shared/images/groupframe_topleft.png
Binary files differ
diff --git a/demos/shared/images/groupframe_topright.png b/demos/shared/images/groupframe_topright.png
new file mode 100644
index 0000000..1a0a328
--- /dev/null
+++ b/demos/shared/images/groupframe_topright.png
Binary files differ
diff --git a/demos/shared/images/line_dash_dot.png b/demos/shared/images/line_dash_dot.png
new file mode 100644
index 0000000..1c61442
--- /dev/null
+++ b/demos/shared/images/line_dash_dot.png
Binary files differ
diff --git a/demos/shared/images/line_dash_dot_dot.png b/demos/shared/images/line_dash_dot_dot.png
new file mode 100644
index 0000000..0d9bb97
--- /dev/null
+++ b/demos/shared/images/line_dash_dot_dot.png
Binary files differ
diff --git a/demos/shared/images/line_dashed.png b/demos/shared/images/line_dashed.png
new file mode 100644
index 0000000..d5bc7ea
--- /dev/null
+++ b/demos/shared/images/line_dashed.png
Binary files differ
diff --git a/demos/shared/images/line_dotted.png b/demos/shared/images/line_dotted.png
new file mode 100644
index 0000000..a2f9a35
--- /dev/null
+++ b/demos/shared/images/line_dotted.png
Binary files differ
diff --git a/demos/shared/images/line_solid.png b/demos/shared/images/line_solid.png
new file mode 100644
index 0000000..60ef3f9
--- /dev/null
+++ b/demos/shared/images/line_solid.png
Binary files differ
diff --git a/demos/shared/images/radiobutton-off.png b/demos/shared/images/radiobutton-off.png
new file mode 100644
index 0000000..af1753a
--- /dev/null
+++ b/demos/shared/images/radiobutton-off.png
Binary files differ
diff --git a/demos/shared/images/radiobutton-on.png b/demos/shared/images/radiobutton-on.png
new file mode 100644
index 0000000..f875838
--- /dev/null
+++ b/demos/shared/images/radiobutton-on.png
Binary files differ
diff --git a/demos/shared/images/radiobutton_off.png b/demos/shared/images/radiobutton_off.png
new file mode 100644
index 0000000..400906e
--- /dev/null
+++ b/demos/shared/images/radiobutton_off.png
Binary files differ
diff --git a/demos/shared/images/radiobutton_on.png b/demos/shared/images/radiobutton_on.png
new file mode 100644
index 0000000..50a049e
--- /dev/null
+++ b/demos/shared/images/radiobutton_on.png
Binary files differ
diff --git a/demos/shared/images/slider_bar.png b/demos/shared/images/slider_bar.png
new file mode 100644
index 0000000..1b3d62c
--- /dev/null
+++ b/demos/shared/images/slider_bar.png
Binary files differ
diff --git a/demos/shared/images/slider_thumb_off.png b/demos/shared/images/slider_thumb_off.png
new file mode 100644
index 0000000..d7f141d
--- /dev/null
+++ b/demos/shared/images/slider_thumb_off.png
Binary files differ
diff --git a/demos/shared/images/slider_thumb_on.png b/demos/shared/images/slider_thumb_on.png
new file mode 100644
index 0000000..8e1f510
--- /dev/null
+++ b/demos/shared/images/slider_thumb_on.png
Binary files differ
diff --git a/demos/shared/images/title_cap_left.png b/demos/shared/images/title_cap_left.png
new file mode 100644
index 0000000..2d47507
--- /dev/null
+++ b/demos/shared/images/title_cap_left.png
Binary files differ
diff --git a/demos/shared/images/title_cap_right.png b/demos/shared/images/title_cap_right.png
new file mode 100644
index 0000000..dc3ff85
--- /dev/null
+++ b/demos/shared/images/title_cap_right.png
Binary files differ
diff --git a/demos/shared/images/title_stretch.png b/demos/shared/images/title_stretch.png
new file mode 100644
index 0000000..1104334
--- /dev/null
+++ b/demos/shared/images/title_stretch.png
Binary files differ
diff --git a/demos/shared/shared.pri b/demos/shared/shared.pri
new file mode 100644
index 0000000..1541fa7
--- /dev/null
+++ b/demos/shared/shared.pri
@@ -0,0 +1,21 @@
+INCLUDEPATH += $$SHARED_FOLDER
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+contains(CONFIG, debug_and_release_target) {
+ CONFIG(debug, debug|release) {
+ LIBS+=-L$$SHARED_FOLDER/debug
+ } else {
+ LIBS+=-L$$SHARED_FOLDER/release
+ }
+} else {
+ LIBS += -L$$SHARED_FOLDER
+}
+
+hpux-acc*:LIBS += $$SHARED_FOLDER/libdemo_shared.a
+hpuxi-acc*:LIBS += $$SHARED_FOLDER/libdemo_shared.a
+symbian:LIBS += -ldemo_shared.lib
+!hpuxi-acc*:!hpux-acc*:!symbian:LIBS += -ldemo_shared
+
diff --git a/demos/shared/shared.pro b/demos/shared/shared.pro
new file mode 100644
index 0000000..a5e0e70
--- /dev/null
+++ b/demos/shared/shared.pro
@@ -0,0 +1,36 @@
+TEMPLATE = lib
+CONFIG += static
+
+contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2) {
+ DEFINES += QT_OPENGL_SUPPORT
+ QT += opengl
+}
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+TARGET = demo_shared
+
+SOURCES += \
+ arthurstyle.cpp\
+ arthurwidgets.cpp \
+ hoverpoints.cpp
+
+HEADERS += \
+ arthurstyle.h \
+ arthurwidgets.h \
+ hoverpoints.h
+
+RESOURCES += shared.qrc
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/shared
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.pri images
+sources.path = $$[QT_INSTALL_DEMOS]/shared
+INSTALLS += sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+!cross_compile:INSTALLS += target
+
+symbian:TARGET.UID3 = 0xA000A63C
diff --git a/demos/shared/shared.qrc b/demos/shared/shared.qrc
new file mode 100644
index 0000000..17336ec
--- /dev/null
+++ b/demos/shared/shared.qrc
@@ -0,0 +1,39 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/res">
+ <file>images/button_normal_cap_left.png</file>
+ <file>images/button_normal_cap_right.png</file>
+ <file>images/button_normal_stretch.png</file>
+ <file>images/button_pressed_cap_left.png</file>
+ <file>images/button_pressed_cap_right.png</file>
+ <file>images/button_pressed_stretch.png</file>
+ <file>images/radiobutton-on.png</file>
+ <file>images/radiobutton_on.png</file>
+ <file>images/radiobutton_off.png</file>
+ <file>images/slider_bar.png</file>
+ <file>images/slider_thumb_on.png</file>
+ <file>images/groupframe_topleft.png</file>
+ <file>images/groupframe_topright.png</file>
+ <file>images/groupframe_bottom_left.png</file>
+ <file>images/groupframe_bottom_right.png</file>
+ <file>images/groupframe_top_stretch.png</file>
+ <file>images/groupframe_bottom_stretch.png</file>
+ <file>images/groupframe_left_stretch.png</file>
+ <file>images/groupframe_right_stretch.png</file>
+ <file>images/frame_topleft.png</file>
+ <file>images/frame_topright.png</file>
+ <file>images/frame_bottomleft.png</file>
+ <file>images/frame_bottomright.png</file>
+ <file>images/frame_left.png</file>
+ <file>images/frame_top.png</file>
+ <file>images/frame_right.png</file>
+ <file>images/frame_bottom.png</file>
+ <file>images/title_cap_left.png</file>
+ <file>images/title_cap_right.png</file>
+ <file>images/title_stretch.png</file>
+ <file>images/line_dash_dot.png</file>
+ <file>images/line_dotted.png</file>
+ <file>images/line_dashed.png</file>
+ <file>images/line_solid.png</file>
+ <file>images/line_dash_dot_dot.png</file>
+</qresource>
+</RCC>
diff --git a/demos/spreadsheet/images/interview.png b/demos/spreadsheet/images/interview.png
new file mode 100644
index 0000000..0c3d690
--- /dev/null
+++ b/demos/spreadsheet/images/interview.png
Binary files differ
diff --git a/demos/spreadsheet/main.cpp b/demos/spreadsheet/main.cpp
new file mode 100644
index 0000000..7a71641
--- /dev/null
+++ b/demos/spreadsheet/main.cpp
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QApplication>
+#include "spreadsheet.h"
+
+int main(int argc, char** argv) {
+ Q_INIT_RESOURCE(spreadsheet);
+ QApplication app(argc, argv);
+ SpreadSheet sheet(10, 6);
+ sheet.setWindowIcon(QPixmap(":/images/interview.png"));
+ sheet.resize(640, 420);
+ sheet.show();
+ return app.exec();
+}
+
+
diff --git a/demos/spreadsheet/printview.cpp b/demos/spreadsheet/printview.cpp
new file mode 100644
index 0000000..76c4ae8
--- /dev/null
+++ b/demos/spreadsheet/printview.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "printview.h"
+#include <QPrinter>
+#include <QStyleOptionViewItem>
+
+PrintView::PrintView()
+{
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+}
+
+void PrintView::print(QPrinter *printer)
+{
+#ifndef QT_NO_PRINTER
+ resize(printer->width(), printer->height());
+ render(printer);
+#endif
+}
+
diff --git a/demos/spreadsheet/printview.h b/demos/spreadsheet/printview.h
new file mode 100644
index 0000000..3f2b918
--- /dev/null
+++ b/demos/spreadsheet/printview.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PRINTVIEW_H
+#define PRINTVIEW_H
+
+#include <QTableView>
+
+class PrintView : public QTableView
+{
+ Q_OBJECT
+
+public:
+ PrintView();
+
+public Q_SLOTS:
+ void print(QPrinter *printer);
+};
+
+#endif // PRINTVIEW_H
+
+
diff --git a/demos/spreadsheet/spreadsheet.cpp b/demos/spreadsheet/spreadsheet.cpp
new file mode 100644
index 0000000..742855e
--- /dev/null
+++ b/demos/spreadsheet/spreadsheet.cpp
@@ -0,0 +1,631 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui>
+#include "spreadsheet.h"
+#include "spreadsheetdelegate.h"
+#include "spreadsheetitem.h"
+#include "printview.h"
+
+SpreadSheet::SpreadSheet(int rows, int cols, QWidget *parent)
+ : QMainWindow(parent)
+{
+ addToolBar(toolBar = new QToolBar());
+ formulaInput = new QLineEdit();
+
+ cellLabel = new QLabel(toolBar);
+ cellLabel->setMinimumSize(80, 0);
+
+ toolBar->addWidget(cellLabel);
+ toolBar->addWidget(formulaInput);
+
+ table = new QTableWidget(rows, cols, this);
+ for (int c = 0; c < cols; ++c) {
+ QString character(QChar('A' + c));
+ table->setHorizontalHeaderItem(c, new QTableWidgetItem(character));
+ }
+
+ table->setItemPrototype(table->item(rows -1, cols - 1));
+ table->setItemDelegate(new SpreadSheetDelegate());
+
+ createActions();
+ updateColor(0);
+ setupMenuBar();
+ setupContents();
+ setCentralWidget(table);
+
+ statusBar();
+ connect(table, SIGNAL(currentItemChanged(QTableWidgetItem*, QTableWidgetItem*)),
+ this, SLOT(updateStatus(QTableWidgetItem*)));
+ connect(table, SIGNAL(currentItemChanged(QTableWidgetItem*, QTableWidgetItem*)),
+ this, SLOT(updateColor(QTableWidgetItem*)));
+ connect(table, SIGNAL(currentItemChanged(QTableWidgetItem*,QTableWidgetItem*)),
+ this, SLOT(updateLineEdit(QTableWidgetItem*)));
+ connect(table, SIGNAL(itemChanged(QTableWidgetItem*)),
+ this, SLOT(updateStatus(QTableWidgetItem*)));
+ connect(formulaInput, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
+ connect(table, SIGNAL(itemChanged(QTableWidgetItem*)),
+ this, SLOT(updateLineEdit(QTableWidgetItem*)));
+
+ setWindowTitle(tr("Spreadsheet"));
+}
+
+void SpreadSheet::createActions()
+{
+ cell_sumAction = new QAction(tr("Sum"), this);
+ connect(cell_sumAction, SIGNAL(triggered()), this, SLOT(actionSum()));
+
+ cell_addAction = new QAction(tr("&Add"), this);
+ cell_addAction->setShortcut(Qt::CTRL | Qt::Key_Plus);
+ connect(cell_addAction, SIGNAL(triggered()), this, SLOT(actionAdd()));
+
+ cell_subAction = new QAction(tr("&Subtract"), this);
+ cell_subAction->setShortcut(Qt::CTRL | Qt::Key_Minus);
+ connect(cell_subAction, SIGNAL(triggered()), this, SLOT(actionSubtract()));
+
+ cell_mulAction = new QAction(tr("&Multiply"), this);
+ cell_mulAction->setShortcut(Qt::CTRL | Qt::Key_multiply);
+ connect(cell_mulAction, SIGNAL(triggered()), this, SLOT(actionMultiply()));
+
+ cell_divAction = new QAction(tr("&Divide"), this);
+ cell_divAction->setShortcut(Qt::CTRL | Qt::Key_division);
+ connect(cell_divAction, SIGNAL(triggered()), this, SLOT(actionDivide()));
+
+ fontAction = new QAction(tr("Font..."), this);
+ fontAction->setShortcut(Qt::CTRL | Qt::Key_F);
+ connect(fontAction, SIGNAL(triggered()), this, SLOT(selectFont()));
+
+ colorAction = new QAction(QPixmap(16, 16), tr("Background &Color..."), this);
+ connect(colorAction, SIGNAL(triggered()), this, SLOT(selectColor()));
+
+ clearAction = new QAction(tr("Clear"), this);
+ clearAction->setShortcut(Qt::Key_Delete);
+ connect(clearAction, SIGNAL(triggered()), this, SLOT(clear()));
+
+ aboutSpreadSheet = new QAction(tr("About Spreadsheet"), this);
+ connect(aboutSpreadSheet, SIGNAL(triggered()), this, SLOT(showAbout()));
+
+ exitAction = new QAction(tr("E&xit"), this);
+ connect(exitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
+
+ printAction = new QAction(tr("&Print"), this);
+ connect(printAction, SIGNAL(triggered()), this, SLOT(print()));
+
+ firstSeparator = new QAction(this);
+ firstSeparator->setSeparator(true);
+
+ secondSeparator = new QAction(this);
+ secondSeparator->setSeparator(true);
+}
+
+void SpreadSheet::setupMenuBar()
+{
+ QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
+ fileMenu->addAction(printAction);
+ fileMenu->addAction(exitAction);
+
+ QMenu *cellMenu = menuBar()->addMenu(tr("&Cell"));
+ cellMenu->addAction(cell_addAction);
+ cellMenu->addAction(cell_subAction);
+ cellMenu->addAction(cell_mulAction);
+ cellMenu->addAction(cell_divAction);
+ cellMenu->addAction(cell_sumAction);
+ cellMenu->addSeparator();
+ cellMenu->addAction(colorAction);
+ cellMenu->addAction(fontAction);
+
+ menuBar()->addSeparator();
+
+ QMenu *aboutMenu = menuBar()->addMenu(tr("&Help"));
+ aboutMenu->addAction(aboutSpreadSheet);
+}
+
+void SpreadSheet::updateStatus(QTableWidgetItem *item)
+{
+ if (item && item == table->currentItem()) {
+ statusBar()->showMessage(item->data(Qt::StatusTipRole).toString(),
+ 1000);
+ cellLabel->setText(tr("Cell: (%1)").arg(encode_pos(table->row(item),
+ table->column(item))));
+ }
+}
+
+void SpreadSheet::updateColor(QTableWidgetItem *item)
+{
+ QPixmap pix(16, 16);
+ QColor col;
+ if (item)
+ col = item->backgroundColor();
+ if (!col.isValid())
+ col = palette().base().color();
+
+ QPainter pt(&pix);
+ pt.fillRect(0, 0, 16, 16, col);
+
+ QColor lighter = col.light();
+ pt.setPen(lighter);
+ QPoint lightFrame[] = { QPoint(0, 15), QPoint(0, 0), QPoint(15, 0) };
+ pt.drawPolyline(lightFrame, 3);
+
+ pt.setPen(col.dark());
+ QPoint darkFrame[] = { QPoint(1, 15), QPoint(15, 15), QPoint(15, 1) };
+ pt.drawPolyline(darkFrame, 3);
+
+ pt.end();
+
+ colorAction->setIcon(pix);
+}
+
+void SpreadSheet::updateLineEdit(QTableWidgetItem *item)
+{
+ if (item != table->currentItem())
+ return;
+ if (item)
+ formulaInput->setText(item->data(Qt::EditRole).toString());
+ else
+ formulaInput->clear();
+}
+
+void SpreadSheet::returnPressed()
+{
+ QString text = formulaInput->text();
+ int row = table->currentRow();
+ int col = table->currentColumn();
+ QTableWidgetItem *item = table->item(row, col);
+ if (!item)
+ table->setItem(row, col, new SpreadSheetItem(text));
+ else
+ item->setData(Qt::EditRole, text);
+ table->viewport()->update();
+}
+
+void SpreadSheet::selectColor()
+{
+ QTableWidgetItem *item = table->currentItem();
+ QColor col = item ? item->backgroundColor() : table->palette().base().color();
+ col = QColorDialog::getColor(col, this);
+ if (!col.isValid())
+ return;
+
+ QList<QTableWidgetItem*> selected = table->selectedItems();
+ if (selected.count() == 0)
+ return;
+
+ foreach(QTableWidgetItem *i, selected)
+ if (i)
+ i->setBackgroundColor(col);
+
+ updateColor(table->currentItem());
+}
+
+void SpreadSheet::selectFont()
+{
+ QList<QTableWidgetItem*> selected = table->selectedItems();
+ if (selected.count() == 0)
+ return;
+
+ bool ok = false;
+ QFont fnt = QFontDialog::getFont(&ok, font(), this);
+
+ if (!ok)
+ return;
+ foreach(QTableWidgetItem *i, selected)
+ if (i)
+ i->setFont(fnt);
+}
+
+bool SpreadSheet::runInputDialog(const QString &title,
+ const QString &c1Text,
+ const QString &c2Text,
+ const QString &opText,
+ const QString &outText,
+ QString *cell1, QString *cell2, QString *outCell)
+{
+ QStringList rows, cols;
+ for (int c = 0; c < table->columnCount(); ++c)
+ cols << QChar('A' + c);
+ for (int r = 0; r < table->rowCount(); ++r)
+ rows << QString::number(1 + r);
+
+ QDialog addDialog(this);
+ addDialog.setWindowTitle(title);
+
+ QGroupBox group(title, &addDialog);
+ group.setMinimumSize(250, 100);
+
+ QLabel cell1Label(c1Text, &group);
+ QComboBox cell1RowInput(&group);
+ int c1Row, c1Col;
+ decode_pos(*cell1, &c1Row, &c1Col);
+ cell1RowInput.addItems(rows);
+ cell1RowInput.setCurrentIndex(c1Row);
+
+ QComboBox cell1ColInput(&group);
+ cell1ColInput.addItems(cols);
+ cell1ColInput.setCurrentIndex(c1Col);
+
+ QLabel operatorLabel(opText, &group);
+ operatorLabel.setAlignment(Qt::AlignHCenter);
+
+ QLabel cell2Label(c2Text, &group);
+ QComboBox cell2RowInput(&group);
+ int c2Row, c2Col;
+ decode_pos(*cell2, &c2Row, &c2Col);
+ cell2RowInput.addItems(rows);
+ cell2RowInput.setCurrentIndex(c2Row);
+ QComboBox cell2ColInput(&group);
+ cell2ColInput.addItems(cols);
+ cell2ColInput.setCurrentIndex(c2Col);
+
+ QLabel equalsLabel("=", &group);
+ equalsLabel.setAlignment(Qt::AlignHCenter);
+
+ QLabel outLabel(outText, &group);
+ QComboBox outRowInput(&group);
+ int outRow, outCol;
+ decode_pos(*outCell, &outRow, &outCol);
+ outRowInput.addItems(rows);
+ outRowInput.setCurrentIndex(outRow);
+ QComboBox outColInput(&group);
+ outColInput.addItems(cols);
+ outColInput.setCurrentIndex(outCol);
+
+ QPushButton cancelButton(tr("Cancel"), &addDialog);
+ connect(&cancelButton, SIGNAL(clicked()), &addDialog, SLOT(reject()));
+
+ QPushButton okButton(tr("OK"), &addDialog);
+ okButton.setDefault(true);
+ connect(&okButton, SIGNAL(clicked()), &addDialog, SLOT(accept()));
+
+ QHBoxLayout *buttonsLayout = new QHBoxLayout;
+ buttonsLayout->addStretch(1);
+ buttonsLayout->addWidget(&okButton);
+ buttonsLayout->addSpacing(10);
+ buttonsLayout->addWidget(&cancelButton);
+
+ QVBoxLayout *dialogLayout = new QVBoxLayout(&addDialog);
+ dialogLayout->addWidget(&group);
+ dialogLayout->addStretch(1);
+ dialogLayout->addItem(buttonsLayout);
+
+ QHBoxLayout *cell1Layout = new QHBoxLayout;
+ cell1Layout->addWidget(&cell1Label);
+ cell1Layout->addSpacing(10);
+ cell1Layout->addWidget(&cell1ColInput);
+ cell1Layout->addSpacing(10);
+ cell1Layout->addWidget(&cell1RowInput);
+
+ QHBoxLayout *cell2Layout = new QHBoxLayout;
+ cell2Layout->addWidget(&cell2Label);
+ cell2Layout->addSpacing(10);
+ cell2Layout->addWidget(&cell2ColInput);
+ cell2Layout->addSpacing(10);
+ cell2Layout->addWidget(&cell2RowInput);
+
+ QHBoxLayout *outLayout = new QHBoxLayout;
+ outLayout->addWidget(&outLabel);
+ outLayout->addSpacing(10);
+ outLayout->addWidget(&outColInput);
+ outLayout->addSpacing(10);
+ outLayout->addWidget(&outRowInput);
+
+ QVBoxLayout *vLayout = new QVBoxLayout(&group);
+ vLayout->addItem(cell1Layout);
+ vLayout->addWidget(&operatorLabel);
+ vLayout->addItem(cell2Layout);
+ vLayout->addWidget(&equalsLabel);
+ vLayout->addStretch(1);
+ vLayout->addItem(outLayout);
+
+ if (addDialog.exec()) {
+ *cell1 = cell1ColInput.currentText() + cell1RowInput.currentText();
+ *cell2 = cell2ColInput.currentText() + cell2RowInput.currentText();
+ *outCell = outColInput.currentText() + outRowInput.currentText();
+ return true;
+ }
+
+ return false;
+}
+
+void SpreadSheet::actionSum()
+{
+ int row_first = 0;
+ int row_last = 0;
+ int row_cur = 0;
+
+ int col_first = 0;
+ int col_last = 0;
+ int col_cur = 0;
+
+ QList<QTableWidgetItem*> selected = table->selectedItems();
+
+ if (!selected.isEmpty()) {
+ QTableWidgetItem *first = selected.first();
+ QTableWidgetItem *last = selected.last();
+ row_first = table->row(first);
+ row_last = table->row(last);
+ col_first = table->column(first);
+ col_last = table->column(last);
+ }
+
+ QTableWidgetItem *current = table->currentItem();
+
+ if (current) {
+ row_cur = table->row(current);
+ col_cur = table->column(current);
+ }
+
+ QString cell1 = encode_pos(row_first, col_first);
+ QString cell2 = encode_pos(row_last, col_last);
+ QString out = encode_pos(row_cur, col_cur);
+
+ if (runInputDialog(tr("Sum cells"), tr("First cell:"), tr("Last cell:"),
+ QString("%1").arg(QChar(0x03a3)), tr("Output to:"),
+ &cell1, &cell2, &out)) {
+ int row, col;
+ decode_pos(out, &row, &col);
+ table->item(row, col)->setText(tr("sum %1 %2").arg(cell1, cell2));
+ }
+}
+
+void SpreadSheet::actionMath_helper(const QString &title, const QString &op)
+{
+ QString cell1 = "C1";
+ QString cell2 = "C2";
+ QString out = "C3";
+
+ QTableWidgetItem *current = table->currentItem();
+ if (current)
+ out = encode_pos(table->currentRow(), table->currentColumn());
+
+ if (runInputDialog(title, tr("Cell 1"), tr("Cell 2"), op, tr("Output to:"),
+ &cell1, &cell2, &out)) {
+ int row, col;
+ decode_pos(out, &row, &col);
+ table->item(row, col)->setText(tr("%1, %2, %3").arg(op, cell1, cell2));
+ }
+}
+
+void SpreadSheet::actionAdd()
+{
+ actionMath_helper(tr("Addition"), "+");
+}
+
+void SpreadSheet::actionSubtract()
+{
+ actionMath_helper(tr("Subtraction"), "-");
+}
+
+void SpreadSheet::actionMultiply()
+{
+ actionMath_helper(tr("Multiplication"), "*");
+}
+void SpreadSheet::actionDivide()
+{
+ actionMath_helper(tr("Division"), "/");
+}
+
+void SpreadSheet::clear()
+{
+ foreach (QTableWidgetItem *i, table->selectedItems())
+ i->setText("");
+}
+
+void SpreadSheet::setupContextMenu()
+{
+ addAction(cell_addAction);
+ addAction(cell_subAction);
+ addAction(cell_mulAction);
+ addAction(cell_divAction);
+ addAction(cell_sumAction);
+ addAction(firstSeparator);
+ addAction(colorAction);
+ addAction(fontAction);
+ addAction(secondSeparator);
+ addAction(clearAction);
+ setContextMenuPolicy(Qt::ActionsContextMenu);
+}
+
+void SpreadSheet::setupContents()
+{
+ QColor titleBackground(Qt::lightGray);
+ QFont titleFont = table->font();
+ titleFont.setBold(true);
+
+ // column 0
+ table->setItem(0, 0, new SpreadSheetItem("Item"));
+ table->item(0, 0)->setBackgroundColor(titleBackground);
+ table->item(0, 0)->setToolTip("This column shows the purchased item/service");
+ table->item(0, 0)->setFont(titleFont);
+
+ table->setItem(1, 0, new SpreadSheetItem("AirportBus"));
+ table->setItem(2, 0, new SpreadSheetItem("Flight (Munich)"));
+ table->setItem(3, 0, new SpreadSheetItem("Lunch"));
+ table->setItem(4, 0, new SpreadSheetItem("Flight (LA)"));
+ table->setItem(5, 0, new SpreadSheetItem("Taxi"));
+ table->setItem(6, 0, new SpreadSheetItem("Diinner"));
+ table->setItem(7, 0, new SpreadSheetItem("Hotel"));
+ table->setItem(8, 0, new SpreadSheetItem("Flight (Oslo)"));
+ table->setItem(9, 0, new SpreadSheetItem("Total:"));
+
+ table->item(9, 0)->setFont(titleFont);
+ table->item(9, 0)->setBackgroundColor(Qt::lightGray);
+
+ // column 1
+ table->setItem(0, 1, new SpreadSheetItem("Date"));
+ table->item(0, 1)->setBackgroundColor(titleBackground);
+ table->item(0, 1)->setToolTip("This column shows the purchase date, double click to change");
+ table->item(0, 1)->setFont(titleFont);
+
+ table->setItem(1, 1, new SpreadSheetItem("15/6/2006"));
+ table->setItem(2, 1, new SpreadSheetItem("15/6/2006"));
+ table->setItem(3, 1, new SpreadSheetItem("15/6/2006"));
+ table->setItem(4, 1, new SpreadSheetItem("21/5/2006"));
+ table->setItem(5, 1, new SpreadSheetItem("16/6/2006"));
+ table->setItem(6, 1, new SpreadSheetItem("16/6/2006"));
+ table->setItem(7, 1, new SpreadSheetItem("16/6/2006"));
+ table->setItem(8, 1, new SpreadSheetItem("18/6/2006"));
+
+ table->setItem(9, 1, new SpreadSheetItem());
+ table->item(9, 1)->setBackgroundColor(Qt::lightGray);
+
+ // column 2
+ table->setItem(0, 2, new SpreadSheetItem("Price"));
+ table->item(0, 2)->setBackgroundColor(titleBackground);
+ table->item(0, 2)->setToolTip("This collumn shows the price of the purchase");
+ table->item(0, 2)->setFont(titleFont);
+
+ table->setItem(1, 2, new SpreadSheetItem("150"));
+ table->setItem(2, 2, new SpreadSheetItem("2350"));
+ table->setItem(3, 2, new SpreadSheetItem("-14"));
+ table->setItem(4, 2, new SpreadSheetItem("980"));
+ table->setItem(5, 2, new SpreadSheetItem("5"));
+ table->setItem(6, 2, new SpreadSheetItem("120"));
+ table->setItem(7, 2, new SpreadSheetItem("300"));
+ table->setItem(8, 2, new SpreadSheetItem("1240"));
+
+ table->setItem(9, 2, new SpreadSheetItem());
+
+ // column 3
+ table->setItem(0, 3, new SpreadSheetItem("Currency"));
+ table->item(0, 3)->setBackgroundColor(titleBackground);
+ table->item(0, 3)->setToolTip("This column shows the currency");
+ table->item(0, 3)->setFont(titleFont);
+
+ table->setItem(1, 3, new SpreadSheetItem("NOK"));
+ table->setItem(2, 3, new SpreadSheetItem("NOK"));
+ table->setItem(3, 3, new SpreadSheetItem("EUR"));
+ table->setItem(4, 3, new SpreadSheetItem("EUR"));
+ table->setItem(5, 3, new SpreadSheetItem("USD"));
+ table->setItem(6, 3, new SpreadSheetItem("USD"));
+ table->setItem(7, 3, new SpreadSheetItem("USD"));
+ table->setItem(8, 3, new SpreadSheetItem("USD"));
+
+ table->setItem(9, 3, new SpreadSheetItem());
+ table->item(9,3)->setBackgroundColor(Qt::lightGray);
+
+ // column 4
+ table->setItem(0, 4, new SpreadSheetItem("Ex. Rate"));
+ table->item(0, 4)->setBackgroundColor(titleBackground);
+ table->item(0, 4)->setToolTip("This column shows the exchange rate to NOK");
+ table->item(0, 4)->setFont(titleFont);
+
+ table->setItem(1, 4, new SpreadSheetItem("1"));
+ table->setItem(2, 4, new SpreadSheetItem("1"));
+ table->setItem(3, 4, new SpreadSheetItem("8"));
+ table->setItem(4, 4, new SpreadSheetItem("8"));
+ table->setItem(5, 4, new SpreadSheetItem("7"));
+ table->setItem(6, 4, new SpreadSheetItem("7"));
+ table->setItem(7, 4, new SpreadSheetItem("7"));
+ table->setItem(8, 4, new SpreadSheetItem("7"));
+
+ table->setItem(9, 4, new SpreadSheetItem());
+ table->item(9,4)->setBackgroundColor(Qt::lightGray);
+
+ // column 5
+ table->setItem(0, 5, new SpreadSheetItem("NOK"));
+ table->item(0, 5)->setBackgroundColor(titleBackground);
+ table->item(0, 5)->setToolTip("This column shows the expenses in NOK");
+ table->item(0, 5)->setFont(titleFont);
+
+ table->setItem(1, 5, new SpreadSheetItem("* C2 E2"));
+ table->setItem(2, 5, new SpreadSheetItem("* C3 E3"));
+ table->setItem(3, 5, new SpreadSheetItem("* C4 E4"));
+ table->setItem(4, 5, new SpreadSheetItem("* C5 E5"));
+ table->setItem(5, 5, new SpreadSheetItem("* C6 E6"));
+ table->setItem(6, 5, new SpreadSheetItem("* C7 E7"));
+ table->setItem(7, 5, new SpreadSheetItem("* C8 E8"));
+ table->setItem(8, 5, new SpreadSheetItem("* C9 E9"));
+
+ table->setItem(9, 5, new SpreadSheetItem("sum F2 F9"));
+ table->item(9,5)->setBackgroundColor(Qt::lightGray);
+}
+
+const char *htmlText =
+"<HTML>"
+"<p><b>This demo shows use of <c>QTableWidget</c> with custom handling for"
+" individual cells.</b></p>"
+"<p>Using a customized table item we make it possible to have dynamic"
+" output in different cells. The content that is implemented for this"
+" particular demo is:"
+"<ul>"
+"<li>Adding two cells.</li>"
+"<li>Subtracting one cell from another.</li>"
+"<li>Multiplying two cells.</li>"
+"<li>Dividing one cell with another.</li>"
+"<li>Summing the contents of an arbitrary number of cells.</li>"
+"</HTML>";
+
+void SpreadSheet::showAbout()
+{
+ QMessageBox::about(this, "About Spreadsheet", htmlText);
+}
+
+void decode_pos(const QString &pos, int *row, int *col)
+{
+ if (pos.isEmpty()) {
+ *col = -1;
+ *row = -1;
+ } else {
+ *col = pos.at(0).toLatin1() - 'A';
+ *row = pos.right(pos.size() - 1).toInt() - 1;
+ }
+}
+
+QString encode_pos(int row, int col)
+{
+ return QString(col + 'A') + QString::number(row + 1);
+}
+
+
+void SpreadSheet::print()
+{
+#ifndef QT_NO_PRINTER
+ QPrinter printer(QPrinter::ScreenResolution);
+ QPrintPreviewDialog dlg(&printer);
+ PrintView view;
+ view.setModel(table->model());
+ connect(&dlg, SIGNAL(paintRequested(QPrinter *)),
+ &view, SLOT(print(QPrinter *)));
+ dlg.exec();
+#endif
+}
+
diff --git a/demos/spreadsheet/spreadsheet.h b/demos/spreadsheet/spreadsheet.h
new file mode 100644
index 0000000..944433d
--- /dev/null
+++ b/demos/spreadsheet/spreadsheet.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPREADSHEET_H
+#define SPREADSHEET_H
+
+#include <QMainWindow>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QLabel;
+class QLineEdit;
+class QToolBar;
+class QTableWidgetItem;
+class QTableWidget;
+QT_END_NAMESPACE
+
+class SpreadSheet : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+
+ SpreadSheet(int rows, int cols, QWidget *parent = 0);
+
+public slots:
+ void updateStatus(QTableWidgetItem *item);
+ void updateColor(QTableWidgetItem *item);
+ void updateLineEdit(QTableWidgetItem *item);
+ void returnPressed();
+ void selectColor();
+ void selectFont();
+ void clear();
+ void showAbout();
+
+ void print();
+
+ void actionSum();
+ void actionSubtract();
+ void actionAdd();
+ void actionMultiply();
+ void actionDivide();
+
+protected:
+ void setupContextMenu();
+ void setupContents();
+
+ void setupMenuBar();
+ void createActions();
+
+ void actionMath_helper(const QString &title, const QString &op);
+ bool runInputDialog(const QString &title,
+ const QString &c1Text,
+ const QString &c2Text,
+ const QString &opText,
+ const QString &outText,
+ QString *cell1, QString *cell2, QString *outCell);
+private:
+ QToolBar *toolBar;
+ QAction *colorAction;
+ QAction *fontAction;
+ QAction *firstSeparator;
+ QAction *cell_sumAction;
+ QAction *cell_addAction;
+ QAction *cell_subAction;
+ QAction *cell_mulAction;
+ QAction *cell_divAction;
+ QAction *secondSeparator;
+ QAction *clearAction;
+ QAction *aboutSpreadSheet;
+ QAction *exitAction;
+
+ QAction *printAction;
+
+ QLabel *cellLabel;
+ QTableWidget *table;
+ QLineEdit *formulaInput;
+
+};
+
+void decode_pos(const QString &pos, int *row, int *col);
+QString encode_pos(int row, int col);
+
+
+#endif // SPREADSHEET_H
+
diff --git a/demos/spreadsheet/spreadsheet.pro b/demos/spreadsheet/spreadsheet.pro
new file mode 100644
index 0000000..39c76da
--- /dev/null
+++ b/demos/spreadsheet/spreadsheet.pro
@@ -0,0 +1,35 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Thu Mar 5 14:39:33 2009
+######################################################################
+
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+
+CONFIG += qt warn_on
+#unix:contains(QT_CONFIG, dbus):QT += dbus
+
+# Input
+HEADERS += printview.h spreadsheet.h spreadsheetdelegate.h spreadsheetitem.h
+SOURCES += main.cpp \
+ printview.cpp \
+ spreadsheet.cpp \
+ spreadsheetdelegate.cpp \
+ spreadsheetitem.cpp
+RESOURCES += spreadsheet.qrc
+
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/spreadsheet
+sources.files = $$SOURCES $$RESOURCES *.pro images
+sources.path = $$[QT_INSTALL_DEMOS]/spreadsheet
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
diff --git a/demos/spreadsheet/spreadsheet.qrc b/demos/spreadsheet/spreadsheet.qrc
new file mode 100644
index 0000000..13f496d
--- /dev/null
+++ b/demos/spreadsheet/spreadsheet.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>images/interview.png</file>
+</qresource>
+</RCC>
diff --git a/demos/spreadsheet/spreadsheetdelegate.cpp b/demos/spreadsheet/spreadsheetdelegate.cpp
new file mode 100644
index 0000000..465c92f
--- /dev/null
+++ b/demos/spreadsheet/spreadsheetdelegate.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "spreadsheetdelegate.h"
+#include <QtGui>
+
+SpreadSheetDelegate::SpreadSheetDelegate(QObject *parent)
+ : QItemDelegate(parent) {}
+
+QWidget *SpreadSheetDelegate::createEditor(QWidget *parent,
+ const QStyleOptionViewItem &,
+ const QModelIndex &index) const
+{
+ if (index.column() == 1) {
+ QDateTimeEdit *editor = new QDateTimeEdit(parent);
+ editor->setDisplayFormat("dd/M/yyy");
+ editor->setCalendarPopup(true);
+ return editor;
+ }
+
+ QLineEdit *editor = new QLineEdit(parent);
+
+ // create a completer with the strings in the column as model
+ QStringList allStrings;
+ for (int i = 1; i<index.model()->rowCount(); i++) {
+ QString strItem(index.model()->data(index.sibling(i, index.column()),
+ Qt::EditRole).toString());
+
+ if (!allStrings.contains(strItem))
+ allStrings.append(strItem);
+ }
+
+ QCompleter *autoComplete = new QCompleter(allStrings);
+ editor->setCompleter(autoComplete);
+ connect(editor, SIGNAL(editingFinished()),
+ this, SLOT(commitAndCloseEditor()));
+ return editor;
+}
+
+void SpreadSheetDelegate::commitAndCloseEditor()
+{
+ QLineEdit *editor = qobject_cast<QLineEdit *>(sender());
+ emit commitData(editor);
+ emit closeEditor(editor);
+}
+
+void SpreadSheetDelegate::setEditorData(QWidget *editor,
+ const QModelIndex &index) const
+{
+ QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
+ if (edit) {
+ edit->setText(index.model()->data(index, Qt::EditRole).toString());
+ } else {
+ QDateTimeEdit *dateEditor = qobject_cast<QDateTimeEdit *>(editor);
+ if (dateEditor) {
+ dateEditor->setDate(QDate::fromString(
+ index.model()->data(index, Qt::EditRole).toString(),
+ "d/M/yy"));
+ }
+ }
+}
+
+void SpreadSheetDelegate::setModelData(QWidget *editor,
+ QAbstractItemModel *model, const QModelIndex &index) const
+{
+ QLineEdit *edit = qobject_cast<QLineEdit *>(editor);
+ if (edit) {
+ model->setData(index, edit->text());
+ } else {
+ QDateTimeEdit *dateEditor = qobject_cast<QDateTimeEdit *>(editor);
+ if (dateEditor) {
+ model->setData(index, dateEditor->date().toString("dd/M/yyy"));
+ }
+ }
+}
+
diff --git a/demos/spreadsheet/spreadsheetdelegate.h b/demos/spreadsheet/spreadsheetdelegate.h
new file mode 100644
index 0000000..3b7b9ac
--- /dev/null
+++ b/demos/spreadsheet/spreadsheetdelegate.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPREADSHEETDELEGATE_H
+#define SPREADSHEETDELEGATE_H
+
+#include <QItemDelegate>
+#include "spreadsheet.h"
+
+class SpreadSheetDelegate : public QItemDelegate
+{
+ Q_OBJECT
+
+public:
+ SpreadSheetDelegate(QObject *parent = 0);
+ QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
+ const QModelIndex &index) const;
+ void setEditorData(QWidget *editor, const QModelIndex &index) const;
+ void setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const;
+
+private slots:
+ void commitAndCloseEditor();
+};
+
+#endif // SPREADSHEETDELEGATE_H
+
diff --git a/demos/spreadsheet/spreadsheetitem.cpp b/demos/spreadsheet/spreadsheetitem.cpp
new file mode 100644
index 0000000..8f94b87
--- /dev/null
+++ b/demos/spreadsheet/spreadsheetitem.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "spreadsheetitem.h"
+
+SpreadSheetItem::SpreadSheetItem()
+ : QTableWidgetItem(), isResolving(false)
+{
+}
+
+SpreadSheetItem::SpreadSheetItem(const QString &text)
+ : QTableWidgetItem(text), isResolving(false)
+{
+}
+
+QTableWidgetItem *SpreadSheetItem::clone() const
+{
+ SpreadSheetItem *item = new SpreadSheetItem();
+ *item = *this;
+ return item;
+}
+
+QVariant SpreadSheetItem::data(int role) const
+{
+ if (role == Qt::EditRole || role == Qt::StatusTipRole)
+ return formula();
+
+ if (role == Qt::DisplayRole)
+ return display();
+
+ QString t = display().toString();
+ bool isNumber = false;
+ int number = t.toInt(&isNumber);
+
+ if (role == Qt::TextColorRole) {
+ if (!isNumber)
+ return qVariantFromValue(QColor(Qt::black));
+ else if (number < 0)
+ return qVariantFromValue(QColor(Qt::red));
+ return qVariantFromValue(QColor(Qt::blue));
+ }
+
+ if (role == Qt::TextAlignmentRole)
+ if (!t.isEmpty() && (t.at(0).isNumber() || t.at(0) == '-'))
+ return (int)(Qt::AlignRight | Qt::AlignVCenter);
+
+ return QTableWidgetItem::data(role);
+ }
+
+void SpreadSheetItem::setData(int role, const QVariant &value)
+{
+ QTableWidgetItem::setData(role, value);
+ if (tableWidget())
+ tableWidget()->viewport()->update();
+}
+
+QVariant SpreadSheetItem::display() const
+{
+ // avoid circular dependencies
+ if (isResolving)
+ return QVariant();
+
+ isResolving = true;
+ QVariant result = computeFormula(formula(), tableWidget(), this);
+ isResolving = false;
+ return result;
+}
+
+QVariant SpreadSheetItem::computeFormula(const QString &formula,
+ const QTableWidget *widget,
+ const QTableWidgetItem *self)
+{
+ // check if the s tring is actually a formula or not
+ QStringList list = formula.split(' ');
+ if (list.isEmpty() || !widget)
+ return formula; // it is a normal string
+
+ QString op = list.value(0).toLower();
+
+ int firstRow = -1;
+ int firstCol = -1;
+ int secondRow = -1;
+ int secondCol = -1;
+
+ if (list.count() > 1)
+ decode_pos(list.value(1), &firstRow, &firstCol);
+
+ if (list.count() > 2)
+ decode_pos(list.value(2), &secondRow, &secondCol);
+
+ const QTableWidgetItem *start = widget->item(firstRow, firstCol);
+ const QTableWidgetItem *end = widget->item(secondRow, secondCol);
+
+ int firstVal = start ? start->text().toInt() : 0;
+ int secondVal = end ? end->text().toInt() : 0;
+
+ QVariant result;
+ if (op == "sum") {
+ int sum = 0;
+ for (int r = firstRow; r <= secondRow; ++r) {
+ for (int c = firstCol; c <= secondCol; ++c) {
+ const QTableWidgetItem *tableItem = widget->item(r, c);
+ if (tableItem && tableItem != self)
+ sum += tableItem->text().toInt();
+ }
+ }
+
+ result = sum;
+ } else if (op == "+") {
+ result = (firstVal + secondVal);
+ } else if (op == "-") {
+ result = (firstVal - secondVal);
+ } else if (op == "*") {
+ result = (firstVal * secondVal);
+ } else if (op == "/") {
+ if (secondVal == 0)
+ result = QString("nan");
+ else
+ result = (firstVal / secondVal);
+ } else if (op == "=") {
+ if (start)
+ result = start->text();
+ } else {
+ result = formula;
+ }
+
+ return result;
+}
+
diff --git a/demos/spreadsheet/spreadsheetitem.h b/demos/spreadsheet/spreadsheetitem.h
new file mode 100644
index 0000000..5996d73
--- /dev/null
+++ b/demos/spreadsheet/spreadsheetitem.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPREADSHEETITEM_H
+#define SPREADSHEETITEM_H
+
+#include <QTableWidgetItem>
+#include <QtGui>
+#include "spreadsheet.h"
+
+class SpreadSheetItem : public QTableWidgetItem
+{
+public:
+ SpreadSheetItem();
+ SpreadSheetItem(const QString &text);
+
+ QTableWidgetItem *clone() const;
+
+ QVariant data(int role) const;
+ void setData(int role, const QVariant &value);
+ QVariant display() const;
+
+ inline QString formula() const
+ { return QTableWidgetItem::data(Qt::DisplayRole).toString(); }
+
+ static QVariant computeFormula(const QString &formula,
+ const QTableWidget *widget,
+ const QTableWidgetItem *self = 0);
+
+private:
+ mutable bool isResolving;
+};
+
+#endif // SPREADSHEETITEM_H
+
diff --git a/demos/sqlbrowser/browser.cpp b/demos/sqlbrowser/browser.cpp
new file mode 100644
index 0000000..f7b24db
--- /dev/null
+++ b/demos/sqlbrowser/browser.cpp
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "browser.h"
+#include "qsqlconnectiondialog.h"
+
+#include <QtGui>
+#include <QtSql>
+
+Browser::Browser(QWidget *parent)
+ : QWidget(parent)
+{
+ setupUi(this);
+
+ table->addAction(insertRowAction);
+ table->addAction(deleteRowAction);
+
+ if (QSqlDatabase::drivers().isEmpty())
+ QMessageBox::information(this, tr("No database drivers found"),
+ tr("This demo requires at least one Qt database driver. "
+ "Please check the documentation how to build the "
+ "Qt SQL plugins."));
+
+ emit statusMessage(tr("Ready."));
+}
+
+Browser::~Browser()
+{
+}
+
+void Browser::exec()
+{
+ QSqlQueryModel *model = new QSqlQueryModel(table);
+ model->setQuery(QSqlQuery(sqlEdit->toPlainText(), connectionWidget->currentDatabase()));
+ table->setModel(model);
+
+ if (model->lastError().type() != QSqlError::NoError)
+ emit statusMessage(model->lastError().text());
+ else if (model->query().isSelect())
+ emit statusMessage(tr("Query OK."));
+ else
+ emit statusMessage(tr("Query OK, number of affected rows: %1").arg(
+ model->query().numRowsAffected()));
+
+ updateActions();
+}
+
+QSqlError Browser::addConnection(const QString &driver, const QString &dbName, const QString &host,
+ const QString &user, const QString &passwd, int port)
+{
+ static int cCount = 0;
+
+ QSqlError err;
+ QSqlDatabase db = QSqlDatabase::addDatabase(driver, QString("Browser%1").arg(++cCount));
+ db.setDatabaseName(dbName);
+ db.setHostName(host);
+ db.setPort(port);
+ if (!db.open(user, passwd)) {
+ err = db.lastError();
+ db = QSqlDatabase();
+ QSqlDatabase::removeDatabase(QString("Browser%1").arg(cCount));
+ }
+ connectionWidget->refresh();
+
+ return err;
+}
+
+void Browser::addConnection()
+{
+ QSqlConnectionDialog dialog(this);
+ if (dialog.exec() != QDialog::Accepted)
+ return;
+
+ if (dialog.useInMemoryDatabase()) {
+ QSqlDatabase::database("in_mem_db", false).close();
+ QSqlDatabase::removeDatabase("in_mem_db");
+ QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "in_mem_db");
+ db.setDatabaseName(":memory:");
+ if (!db.open())
+ QMessageBox::warning(this, tr("Unable to open database"), tr("An error occurred while "
+ "opening the connection: ") + db.lastError().text());
+ QSqlQuery q("", db);
+ q.exec("drop table Movies");
+ q.exec("drop table Names");
+ q.exec("create table Movies (id integer primary key, Title varchar, Director varchar, Rating number)");
+ q.exec("insert into Movies values (0, 'Metropolis', 'Fritz Lang', '8.4')");
+ q.exec("insert into Movies values (1, 'Nosferatu, eine Symphonie des Grauens', 'F.W. Murnau', '8.1')");
+ q.exec("insert into Movies values (2, 'Bis ans Ende der Welt', 'Wim Wenders', '6.5')");
+ q.exec("insert into Movies values (3, 'Hardware', 'Richard Stanley', '5.2')");
+ q.exec("insert into Movies values (4, 'Mitchell', 'Andrew V. McLaglen', '2.1')");
+ q.exec("create table Names (id integer primary key, Firstname varchar, Lastname varchar, City varchar)");
+ q.exec("insert into Names values (0, 'Sala', 'Palmer', 'Morristown')");
+ q.exec("insert into Names values (1, 'Christopher', 'Walker', 'Morristown')");
+ q.exec("insert into Names values (2, 'Donald', 'Duck', 'Andeby')");
+ q.exec("insert into Names values (3, 'Buck', 'Rogers', 'Paris')");
+ q.exec("insert into Names values (4, 'Sherlock', 'Holmes', 'London')");
+ connectionWidget->refresh();
+ } else {
+ QSqlError err = addConnection(dialog.driverName(), dialog.databaseName(), dialog.hostName(),
+ dialog.userName(), dialog.password(), dialog.port());
+ if (err.type() != QSqlError::NoError)
+ QMessageBox::warning(this, tr("Unable to open database"), tr("An error occurred while "
+ "opening the connection: ") + err.text());
+ }
+}
+
+void Browser::showTable(const QString &t)
+{
+ QSqlTableModel *model = new QSqlTableModel(table, connectionWidget->currentDatabase());
+ model->setEditStrategy(QSqlTableModel::OnRowChange);
+ model->setTable(t);
+ model->select();
+ if (model->lastError().type() != QSqlError::NoError)
+ emit statusMessage(model->lastError().text());
+ table->setModel(model);
+ table->setEditTriggers(QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed);
+
+ connect(table->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
+ this, SLOT(currentChanged()));
+ updateActions();
+}
+
+void Browser::showMetaData(const QString &t)
+{
+ QSqlRecord rec = connectionWidget->currentDatabase().record(t);
+ QStandardItemModel *model = new QStandardItemModel(table);
+
+ model->insertRows(0, rec.count());
+ model->insertColumns(0, 7);
+
+ model->setHeaderData(0, Qt::Horizontal, "Fieldname");
+ model->setHeaderData(1, Qt::Horizontal, "Type");
+ model->setHeaderData(2, Qt::Horizontal, "Length");
+ model->setHeaderData(3, Qt::Horizontal, "Precision");
+ model->setHeaderData(4, Qt::Horizontal, "Required");
+ model->setHeaderData(5, Qt::Horizontal, "AutoValue");
+ model->setHeaderData(6, Qt::Horizontal, "DefaultValue");
+
+
+ for (int i = 0; i < rec.count(); ++i) {
+ QSqlField fld = rec.field(i);
+ model->setData(model->index(i, 0), fld.name());
+ model->setData(model->index(i, 1), fld.typeID() == -1
+ ? QString(QVariant::typeToName(fld.type()))
+ : QString("%1 (%2)").arg(QVariant::typeToName(fld.type())).arg(fld.typeID()));
+ model->setData(model->index(i, 2), fld.length());
+ model->setData(model->index(i, 3), fld.precision());
+ model->setData(model->index(i, 4), fld.requiredStatus() == -1 ? QVariant("?")
+ : QVariant(bool(fld.requiredStatus())));
+ model->setData(model->index(i, 5), fld.isAutoValue());
+ model->setData(model->index(i, 6), fld.defaultValue());
+ }
+
+ table->setModel(model);
+ table->setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+ updateActions();
+}
+
+void Browser::insertRow()
+{
+ QSqlTableModel *model = qobject_cast<QSqlTableModel *>(table->model());
+ if (!model)
+ return;
+
+ QModelIndex insertIndex = table->currentIndex();
+ int row = insertIndex.row() == -1 ? 0 : insertIndex.row();
+ model->insertRow(row);
+ insertIndex = model->index(row, 0);
+ table->setCurrentIndex(insertIndex);
+ table->edit(insertIndex);
+}
+
+void Browser::deleteRow()
+{
+ QSqlTableModel *model = qobject_cast<QSqlTableModel *>(table->model());
+ if (!model)
+ return;
+
+ model->setEditStrategy(QSqlTableModel::OnManualSubmit);
+
+ QModelIndexList currentSelection = table->selectionModel()->selectedIndexes();
+ for (int i = 0; i < currentSelection.count(); ++i) {
+ if (currentSelection.at(i).column() != 0)
+ continue;
+ model->removeRow(currentSelection.at(i).row());
+ }
+
+ model->submitAll();
+ model->setEditStrategy(QSqlTableModel::OnRowChange);
+
+ updateActions();
+}
+
+void Browser::updateActions()
+{
+ bool enableIns = qobject_cast<QSqlTableModel *>(table->model());
+ bool enableDel = enableIns && table->currentIndex().isValid();
+
+ insertRowAction->setEnabled(enableIns);
+ deleteRowAction->setEnabled(enableDel);
+}
+
+void Browser::about()
+{
+ QMessageBox::about(this, tr("About"), tr("The SQL Browser demonstration "
+ "show how a data browser can be used to visualize the results of SQL"
+ "statements on a live database"));
+}
diff --git a/demos/sqlbrowser/browser.h b/demos/sqlbrowser/browser.h
new file mode 100644
index 0000000..787675b
--- /dev/null
+++ b/demos/sqlbrowser/browser.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BROWSER_H
+#define BROWSER_H
+
+#include <QWidget>
+#include "ui_browserwidget.h"
+
+class ConnectionWidget;
+QT_FORWARD_DECLARE_CLASS(QTableView)
+QT_FORWARD_DECLARE_CLASS(QPushButton)
+QT_FORWARD_DECLARE_CLASS(QTextEdit)
+QT_FORWARD_DECLARE_CLASS(QSqlError)
+
+class Browser: public QWidget, private Ui::Browser
+{
+ Q_OBJECT
+public:
+ Browser(QWidget *parent = 0);
+ virtual ~Browser();
+
+ QSqlError addConnection(const QString &driver, const QString &dbName, const QString &host,
+ const QString &user, const QString &passwd, int port = -1);
+
+ void insertRow();
+ void deleteRow();
+ void updateActions();
+
+public slots:
+ void exec();
+ void showTable(const QString &table);
+ void showMetaData(const QString &table);
+ void addConnection();
+ void currentChanged() { updateActions(); }
+ void about();
+
+ void on_insertRowAction_triggered()
+ { insertRow(); }
+ void on_deleteRowAction_triggered()
+ { deleteRow(); }
+ void on_connectionWidget_tableActivated(const QString &table)
+ { showTable(table); }
+ void on_connectionWidget_metaDataRequested(const QString &table)
+ { showMetaData(table); }
+ void on_submitButton_clicked()
+ {
+ exec();
+ sqlEdit->setFocus();
+ }
+ void on_clearButton_clicked()
+ {
+ sqlEdit->clear();
+ sqlEdit->setFocus();
+ }
+
+signals:
+ void statusMessage(const QString &message);
+};
+
+#endif
diff --git a/demos/sqlbrowser/browserwidget.ui b/demos/sqlbrowser/browserwidget.ui
new file mode 100644
index 0000000..20946f0
--- /dev/null
+++ b/demos/sqlbrowser/browserwidget.ui
@@ -0,0 +1,199 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>Browser</class>
+ <widget class="QWidget" name="Browser" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>765</width>
+ <height>515</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Qt SQL Browser</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QSplitter" name="splitter_2" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="ConnectionWidget" name="connectionWidget" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>13</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QTableView" name="table" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>2</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="contextMenuPolicy" >
+ <enum>Qt::ActionsContextMenu</enum>
+ </property>
+ <property name="selectionBehavior" >
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>16777215</width>
+ <height>180</height>
+ </size>
+ </property>
+ <property name="title" >
+ <string>SQL Query</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QTextEdit" name="sqlEdit" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>18</height>
+ </size>
+ </property>
+ <property name="baseSize" >
+ <size>
+ <width>0</width>
+ <height>120</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>1</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="clearButton" >
+ <property name="text" >
+ <string>&amp;Clear</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="submitButton" >
+ <property name="text" >
+ <string>&amp;Submit</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ <action name="insertRowAction" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>&amp;Insert Row</string>
+ </property>
+ <property name="statusTip" >
+ <string>Inserts a new Row</string>
+ </property>
+ </action>
+ <action name="deleteRowAction" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>&amp;Delete Row</string>
+ </property>
+ <property name="statusTip" >
+ <string>Deletes the current Row</string>
+ </property>
+ </action>
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <customwidgets>
+ <customwidget>
+ <class>ConnectionWidget</class>
+ <extends>QTreeView</extends>
+ <header>connectionwidget.h</header>
+ <container>0</container>
+ <pixmap></pixmap>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>sqlEdit</tabstop>
+ <tabstop>clearButton</tabstop>
+ <tabstop>submitButton</tabstop>
+ <tabstop>connectionWidget</tabstop>
+ <tabstop>table</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/demos/sqlbrowser/connectionwidget.cpp b/demos/sqlbrowser/connectionwidget.cpp
new file mode 100644
index 0000000..7df28ac
--- /dev/null
+++ b/demos/sqlbrowser/connectionwidget.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "connectionwidget.h"
+
+#include <QtGui>
+#include <QtSql>
+
+ConnectionWidget::ConnectionWidget(QWidget *parent)
+ : QWidget(parent)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ tree = new QTreeWidget(this);
+ tree->setObjectName(QLatin1String("tree"));
+ tree->setHeaderLabels(QStringList(tr("database")));
+ tree->header()->setResizeMode(QHeaderView::Stretch);
+ QAction *refreshAction = new QAction(tr("Refresh"), tree);
+ metaDataAction = new QAction(tr("Show Schema"), tree);
+ connect(refreshAction, SIGNAL(triggered()), SLOT(refresh()));
+ connect(metaDataAction, SIGNAL(triggered()), SLOT(showMetaData()));
+ tree->addAction(refreshAction);
+ tree->addAction(metaDataAction);
+ tree->setContextMenuPolicy(Qt::ActionsContextMenu);
+
+ layout->addWidget(tree);
+
+ QMetaObject::connectSlotsByName(this);
+}
+
+ConnectionWidget::~ConnectionWidget()
+{
+}
+
+static QString qDBCaption(const QSqlDatabase &db)
+{
+ QString nm = db.driverName();
+ nm.append(QLatin1Char(':'));
+ if (!db.userName().isEmpty())
+ nm.append(db.userName()).append(QLatin1Char('@'));
+ nm.append(db.databaseName());
+ return nm;
+}
+
+void ConnectionWidget::refresh()
+{
+ tree->clear();
+ QStringList connectionNames = QSqlDatabase::connectionNames();
+
+ bool gotActiveDb = false;
+ for (int i = 0; i < connectionNames.count(); ++i) {
+ QTreeWidgetItem *root = new QTreeWidgetItem(tree);
+ QSqlDatabase db = QSqlDatabase::database(connectionNames.at(i), false);
+ root->setText(0, qDBCaption(db));
+ if (connectionNames.at(i) == activeDb) {
+ gotActiveDb = true;
+ setActive(root);
+ }
+ if (db.isOpen()) {
+ QStringList tables = db.tables();
+ for (int t = 0; t < tables.count(); ++t) {
+ QTreeWidgetItem *table = new QTreeWidgetItem(root);
+ table->setText(0, tables.at(t));
+ }
+ }
+ }
+ if (!gotActiveDb) {
+ activeDb = connectionNames.value(0);
+ setActive(tree->topLevelItem(0));
+ }
+
+ tree->doItemsLayout(); // HACK
+}
+
+QSqlDatabase ConnectionWidget::currentDatabase() const
+{
+ return QSqlDatabase::database(activeDb);
+}
+
+static void qSetBold(QTreeWidgetItem *item, bool bold)
+{
+ QFont font = item->font(0);
+ font.setBold(bold);
+ item->setFont(0, font);
+}
+
+void ConnectionWidget::setActive(QTreeWidgetItem *item)
+{
+ for (int i = 0; i < tree->topLevelItemCount(); ++i) {
+ if (tree->topLevelItem(i)->font(0).bold())
+ qSetBold(tree->topLevelItem(i), false);
+ }
+
+ if (!item)
+ return;
+
+ qSetBold(item, true);
+ activeDb = QSqlDatabase::connectionNames().value(tree->indexOfTopLevelItem(item));
+}
+
+void ConnectionWidget::on_tree_itemActivated(QTreeWidgetItem *item, int /* column */)
+{
+
+ if (!item)
+ return;
+
+ if (!item->parent()) {
+ setActive(item);
+ } else {
+ setActive(item->parent());
+ emit tableActivated(item->text(0));
+ }
+}
+
+void ConnectionWidget::showMetaData()
+{
+ QTreeWidgetItem *cItem = tree->currentItem();
+ if (!cItem || !cItem->parent())
+ return;
+ setActive(cItem->parent());
+ emit metaDataRequested(cItem->text(0));
+}
+
+void ConnectionWidget::on_tree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *)
+{
+ metaDataAction->setEnabled(current && current->parent());
+}
+
diff --git a/demos/sqlbrowser/connectionwidget.h b/demos/sqlbrowser/connectionwidget.h
new file mode 100644
index 0000000..5c48414
--- /dev/null
+++ b/demos/sqlbrowser/connectionwidget.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CONNECTIONWIDGET_H
+#define CONNECTIONWIDGET_H
+
+#include <QWidget>
+
+QT_FORWARD_DECLARE_CLASS(QTreeWidget)
+QT_FORWARD_DECLARE_CLASS(QTreeWidgetItem)
+QT_FORWARD_DECLARE_CLASS(QSqlDatabase)
+QT_FORWARD_DECLARE_CLASS(QMenu)
+
+class ConnectionWidget: public QWidget
+{
+ Q_OBJECT
+public:
+ ConnectionWidget(QWidget *parent = 0);
+ virtual ~ConnectionWidget();
+
+ QSqlDatabase currentDatabase() const;
+
+signals:
+ void tableActivated(const QString &table);
+ void metaDataRequested(const QString &tableName);
+
+public slots:
+ void refresh();
+ void showMetaData();
+ void on_tree_itemActivated(QTreeWidgetItem *item, int column);
+ void on_tree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
+
+private:
+ void setActive(QTreeWidgetItem *);
+
+ QTreeWidget *tree;
+ QAction *metaDataAction;
+ QString activeDb;
+};
+
+#endif
diff --git a/demos/sqlbrowser/main.cpp b/demos/sqlbrowser/main.cpp
new file mode 100644
index 0000000..b7b7fe5
--- /dev/null
+++ b/demos/sqlbrowser/main.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "browser.h"
+
+#include <QtCore>
+#include <QtGui>
+#include <QtSql>
+
+void addConnectionsFromCommandline(const QStringList &args, Browser *browser)
+{
+ for (int i = 1; i < args.count(); ++i) {
+ QUrl url(args.at(i), QUrl::TolerantMode);
+ if (!url.isValid()) {
+ qWarning("Invalid URL: %s", qPrintable(args.at(i)));
+ continue;
+ }
+ QSqlError err = browser->addConnection(url.scheme(), url.path().mid(1), url.host(),
+ url.userName(), url.password(), url.port(-1));
+ if (err.type() != QSqlError::NoError)
+ qDebug() << "Unable to open connection:" << err;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ QMainWindow mainWin;
+ mainWin.setWindowTitle(QObject::tr("Qt SQL Browser"));
+
+ Browser browser(&mainWin);
+ mainWin.setCentralWidget(&browser);
+
+ QMenu *fileMenu = mainWin.menuBar()->addMenu(QObject::tr("&File"));
+ fileMenu->addAction(QObject::tr("Add &Connection..."), &browser, SLOT(addConnection()));
+ fileMenu->addSeparator();
+ fileMenu->addAction(QObject::tr("&Quit"), &app, SLOT(quit()));
+
+ QMenu *helpMenu = mainWin.menuBar()->addMenu(QObject::tr("&Help"));
+ helpMenu->addAction(QObject::tr("About"), &browser, SLOT(about()));
+ helpMenu->addAction(QObject::tr("About Qt"), qApp, SLOT(aboutQt()));
+
+ QObject::connect(&browser, SIGNAL(statusMessage(QString)),
+ mainWin.statusBar(), SLOT(showMessage(QString)));
+
+ addConnectionsFromCommandline(app.arguments(), &browser);
+ mainWin.show();
+ if (QSqlDatabase::connectionNames().isEmpty())
+ QMetaObject::invokeMethod(&browser, "addConnection", Qt::QueuedConnection);
+
+ return app.exec();
+}
diff --git a/demos/sqlbrowser/qsqlconnectiondialog.cpp b/demos/sqlbrowser/qsqlconnectiondialog.cpp
new file mode 100644
index 0000000..a2e3c89
--- /dev/null
+++ b/demos/sqlbrowser/qsqlconnectiondialog.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsqlconnectiondialog.h"
+#include "ui_qsqlconnectiondialog.h"
+
+#include <QSqlDatabase>
+
+QSqlConnectionDialog::QSqlConnectionDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+
+ QStringList drivers = QSqlDatabase::drivers();
+
+ // remove compat names
+ drivers.removeAll("QMYSQL3");
+ drivers.removeAll("QOCI8");
+ drivers.removeAll("QODBC3");
+ drivers.removeAll("QPSQL7");
+ drivers.removeAll("QTDS7");
+
+ if (!drivers.contains("QSQLITE"))
+ ui.dbCheckBox->setEnabled(false);
+
+ ui.comboDriver->addItems(drivers);
+}
+
+QSqlConnectionDialog::~QSqlConnectionDialog()
+{
+}
+
+QString QSqlConnectionDialog::driverName() const
+{
+ return ui.comboDriver->currentText();
+}
+
+QString QSqlConnectionDialog::databaseName() const
+{
+ return ui.editDatabase->text();
+}
+
+QString QSqlConnectionDialog::userName() const
+{
+ return ui.editUsername->text();
+}
+
+QString QSqlConnectionDialog::password() const
+{
+ return ui.editPassword->text();
+}
+
+QString QSqlConnectionDialog::hostName() const
+{
+ return ui.editHostname->text();
+}
+
+int QSqlConnectionDialog::port() const
+{
+ return ui.portSpinBox->value();
+}
+
+bool QSqlConnectionDialog::useInMemoryDatabase() const
+{
+ return ui.dbCheckBox->isChecked();
+}
+
+void QSqlConnectionDialog::on_okButton_clicked()
+{
+ if (ui.comboDriver->currentText().isEmpty()) {
+ QMessageBox::information(this, tr("No database driver selected"),
+ tr("Please select a database driver"));
+ ui.comboDriver->setFocus();
+ } else {
+ accept();
+ }
+}
diff --git a/demos/sqlbrowser/qsqlconnectiondialog.h b/demos/sqlbrowser/qsqlconnectiondialog.h
new file mode 100644
index 0000000..d5f3456
--- /dev/null
+++ b/demos/sqlbrowser/qsqlconnectiondialog.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSQLCONNECTIONDIALOG_H
+#define QSQLCONNECTIONDIALOG_H
+
+#include <QDialog>
+#include <QMessageBox>
+
+#include "ui_qsqlconnectiondialog.h"
+
+class QSqlConnectionDialog: public QDialog
+{
+ Q_OBJECT
+public:
+ QSqlConnectionDialog(QWidget *parent = 0);
+ ~QSqlConnectionDialog();
+
+ QString driverName() const;
+ QString databaseName() const;
+ QString userName() const;
+ QString password() const;
+ QString hostName() const;
+ int port() const;
+ bool useInMemoryDatabase() const;
+
+private slots:
+ void on_okButton_clicked();
+ void on_cancelButton_clicked() { reject(); }
+ void on_dbCheckBox_clicked() { ui.connGroupBox->setEnabled(!ui.dbCheckBox->isChecked()); }
+
+private:
+ Ui::QSqlConnectionDialogUi ui;
+};
+
+#endif
diff --git a/demos/sqlbrowser/qsqlconnectiondialog.ui b/demos/sqlbrowser/qsqlconnectiondialog.ui
new file mode 100644
index 0000000..91a8700
--- /dev/null
+++ b/demos/sqlbrowser/qsqlconnectiondialog.ui
@@ -0,0 +1,224 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>QSqlConnectionDialogUi</class>
+ <widget class="QDialog" name="QSqlConnectionDialogUi" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>315</width>
+ <height>302</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Connect...</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="connGroupBox" >
+ <property name="title" >
+ <string>Connection settings</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="comboDriver" />
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="textLabel4" >
+ <property name="text" >
+ <string>&amp;Username:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>editUsername</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="textLabel2" >
+ <property name="text" >
+ <string>D&amp;river</string>
+ </property>
+ <property name="buddy" >
+ <cstring>comboDriver</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="editDatabase" />
+ </item>
+ <item row="5" column="1" >
+ <widget class="QSpinBox" name="portSpinBox" >
+ <property name="specialValueText" >
+ <string>Default</string>
+ </property>
+ <property name="maximum" >
+ <number>65535</number>
+ </property>
+ <property name="minimum" >
+ <number>-1</number>
+ </property>
+ <property name="value" >
+ <number>-1</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="textLabel3" >
+ <property name="text" >
+ <string>Database Name:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>editDatabase</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLineEdit" name="editPassword" >
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLineEdit" name="editUsername" />
+ </item>
+ <item row="4" column="1" >
+ <widget class="QLineEdit" name="editHostname" />
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="textLabel5" >
+ <property name="text" >
+ <string>&amp;Hostname:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>editHostname</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="textLabel5_2" >
+ <property name="text" >
+ <string>P&amp;ort:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>portSpinBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="textLabel4_2" >
+ <property name="text" >
+ <string>&amp;Password:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>editPassword</cstring>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="dbCheckBox" >
+ <property name="text" >
+ <string>Us&amp;e predefined in-memory database</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton" >
+ <property name="text" >
+ <string>&amp;OK</string>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="text" >
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <tabstops>
+ <tabstop>comboDriver</tabstop>
+ <tabstop>editDatabase</tabstop>
+ <tabstop>editUsername</tabstop>
+ <tabstop>editPassword</tabstop>
+ <tabstop>editHostname</tabstop>
+ <tabstop>portSpinBox</tabstop>
+ <tabstop>dbCheckBox</tabstop>
+ <tabstop>okButton</tabstop>
+ <tabstop>cancelButton</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/demos/sqlbrowser/sqlbrowser.pro b/demos/sqlbrowser/sqlbrowser.pro
new file mode 100644
index 0000000..1334bc1
--- /dev/null
+++ b/demos/sqlbrowser/sqlbrowser.pro
@@ -0,0 +1,25 @@
+TEMPLATE = app
+TARGET = sqlbrowser
+
+QT += sql
+
+HEADERS = browser.h connectionwidget.h qsqlconnectiondialog.h
+SOURCES = main.cpp browser.cpp connectionwidget.cpp qsqlconnectiondialog.cpp
+
+FORMS = browserwidget.ui qsqlconnectiondialog.ui
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/sqlbrowser
+sources.files = $$SOURCES $$HEADERS $$FORMS *.pro
+sources.path = $$[QT_INSTALL_DEMOS]/sqlbrowser
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
+wince*: {
+ DEPLOYMENT_PLUGIN += qsqlite
+}
diff --git a/demos/textedit/example.html b/demos/textedit/example.html
new file mode 100644
index 0000000..19b5520
--- /dev/null
+++ b/demos/textedit/example.html
@@ -0,0 +1,79 @@
+<html><head><meta name="qrichtext" content="1" /><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>QTextEdit Demonstration</title><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
+<p align="center" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:20pt; font-weight:600;">QTextEdit</span></p>
+<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">The QTextEdit widget is an advanced editor that supports formatted rich text. It can be used to display HTML and other rich document formats. Internally, QTextEdit uses the QTextDocument class to describe both the high-level structure of each document and the low-level formatting of paragraphs.</span></p>
+<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;">If you are viewing this document in the <span style=" font-style:italic;">textedit</span> demo, you can edit this document to explore Qt's rich text editing features. We have included some comments in each of the following sections to encourage you to experiment. </p>
+<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:18pt; font-weight:600;"><span style=" font-size:16pt;">Font and Paragraph Styles</span></p>
+<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">QTextEdit supports </span><span style=" font-size:11pt; font-weight:600;">bold</span><span style=" font-size:11pt;">, </span><span style=" font-size:11pt; font-style:italic;">italic</span><span style=" font-size:11pt;">, and </span><span style=" font-size:11pt; text-decoration: underline;">underlined</span><span style=" font-size:11pt;"> font styles, and can display </span><span style=" font-size:11pt; font-weight:600; color:#00007f;">multicolored</span><span style=" font-size:11pt;"> </span><span style=" font-size:11pt; font-weight:600; color:#aa0000;">text</span><span style=" font-size:11pt;">. Font families such as </span><span style=" font-family:'Times'; font-size:11pt; font-weight:600;">Times New Roman</span><span style=" font-size:11pt;"> and </span><span style=" font-family:'Courier'; font-size:11pt; font-weight:600;">Courier</span><span style=" font-size:11pt;"> can also be used directly. </span><span style=" font-size:11pt; font-style:italic;">If you place the cursor in a region of styled text, the controls in the tool bars will change to reflect the current style.</span></p>
+<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;">Paragraphs can be formatted so that the text is left-aligned, right-aligned, centered, or fully justified.</p>
+<p align="center" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><span style=" font-style:italic;">Try changing the alignment of some text and resize the editor to see how the text layout changes.</span> </p>
+<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:16pt; font-weight:600;">Lists</span></p>
+<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:16pt; font-weight:600;"><span style=" font-size:11pt; font-weight:400;">Different kinds of lists can be included in rich text documents. Standard bullet lists can be nested, using different symbols for each level of the list: </span></p>
+<ul style="-qt-list-indent: 1;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Disc symbols are typically used for top-level list items. </li></ul>
+<ul type=circle style="-qt-list-indent: 2;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Circle symbols can be used to distinguish between items in lower-level lists.</li></ul>
+<ul type=square style="-qt-list-indent: 3;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Square symbols provide a reasonable alternative to discs and circles. </li></ul>
+<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;">Ordered lists can be created that can be used for tables of contents. Different characters can be used to enumerate items, and we can use both Roman and Arabic numerals in the same list structure: </p>
+<ol style="-qt-list-indent: 1;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Introduction</li>
+<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Tools </li></ol>
+<ol type=a style="-qt-list-indent: 2;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Assistant</li>
+<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Designer</li>
+<ol type=A style="-qt-list-indent: 3;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Form Editor</li>
+<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Component Architecture</li></ol>
+<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Linguist</li></ol>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;">The list will automatically be renumbered if you add or remove items. <span style=" font-style:italic;">Try adding new sections to the above list or removing existing item to see the numbers change.</span> </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"></p>
+<p style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><span style=" font-size:16pt; font-weight:600;">Images</span></p>
+<p style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:16pt; font-weight:600;"><span style=" font-size:11pt; font-weight:400;">Inline images are treated like ordinary ranges of characters in the text editor, so they flow with the surrounding text. Images can also be selected in the same way as text, making it easy to cut, copy, and paste them. </span></p>
+<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><img src=":/images/logo32.png" /><span style=" font-style:italic;"> Try to select this image by clicking and dragging over it with the mouse, or use the text cursor to select it by holding down Shift and using the arrow keys. You can then cut or copy it, and pasting it into different parts of this document.</span></p>
+<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><span style=" font-size:16pt; font-weight:600;">Tables</span></p>
+<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:16pt; font-weight:600;"><span style=" font-size:11pt; font-weight:400;">QTextEdit can arrange and format tables, supporting features such as row and column spans, text formatting within cells, and size constraints for columns. </span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"></p>
+<table border="1" align="center" width="90%" cellspacing="0" cellpadding="4">
+<tr>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p></td>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Development Tools </span></p></td>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Programming Techniques </span></p></td>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Graphical User Interfaces </span></p></td></tr>
+<tr>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">9:00 - 11:00 </span></p></td>
+<td colspan="3">
+<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Introduction to <span style=" font-style:italic;">Qt </span></p></td></tr>
+<tr>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">11:00 - 13:00 </span></p></td>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Using <span style=" font-style:italic;">qmake</span> </p></td>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Object-oriented Programming </p></td>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Layouts in <span style=" font-style:italic;">Qt</span> </p></td></tr>
+<tr>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">13:00 - 15:00 </span></p></td>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Qt Designer</span> Tutorial </p></td>
+<td rowspan="2">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Extreme Programming </p></td>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Writing Custom Styles </p></td></tr>
+<tr>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">15:00 - 17:00 </span></p></td>
+<td>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Qt Linguist</span> and Internationalization </p></td>
+<td></td></tr></table>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"></p>
+<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt; font-style:italic;">Try adding text to the cells in the table and experiment with the alignment of the paragraphs.</p>
+<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><span style=" font-size:16pt; font-weight:600;">Hyperlinks</span></p>
+<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">QTextEdit is designed to support hyperlinks between documents, and this feature is used extensively in </span><span style=" font-size:11pt; font-style:italic;">Qt Assistant</span><span style=" font-size:11pt;">. Hyperlinks are automatically created when an HTML file is imported into an editor. Since the rich text framework supports hyperlinks natively, they can also be created programatically.</span></p>
+<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><span style=" font-size:16pt; font-weight:600;">Undo and Redo</span></p>
+<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;">Full support for undo and redo operations is built into QTextEdit and the underlying rich text framework. Operations on a document can be packaged together to make editing a more comfortable experience for the user.</p>
+<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><span style=" font-style:italic;">Try making changes to this document and press Ctrl+Z to undo them. You can always recover the original contents of the document.</span> </p></body></html>
diff --git a/demos/textedit/images/logo32.png b/demos/textedit/images/logo32.png
new file mode 100644
index 0000000..5f91e98
--- /dev/null
+++ b/demos/textedit/images/logo32.png
Binary files differ
diff --git a/demos/textedit/images/mac/editcopy.png b/demos/textedit/images/mac/editcopy.png
new file mode 100644
index 0000000..f551364
--- /dev/null
+++ b/demos/textedit/images/mac/editcopy.png
Binary files differ
diff --git a/demos/textedit/images/mac/editcut.png b/demos/textedit/images/mac/editcut.png
new file mode 100644
index 0000000..a784fd5
--- /dev/null
+++ b/demos/textedit/images/mac/editcut.png
Binary files differ
diff --git a/demos/textedit/images/mac/editpaste.png b/demos/textedit/images/mac/editpaste.png
new file mode 100644
index 0000000..64c0b2d
--- /dev/null
+++ b/demos/textedit/images/mac/editpaste.png
Binary files differ
diff --git a/demos/textedit/images/mac/editredo.png b/demos/textedit/images/mac/editredo.png
new file mode 100644
index 0000000..8875bf2
--- /dev/null
+++ b/demos/textedit/images/mac/editredo.png
Binary files differ
diff --git a/demos/textedit/images/mac/editundo.png b/demos/textedit/images/mac/editundo.png
new file mode 100644
index 0000000..a3bd5e0
--- /dev/null
+++ b/demos/textedit/images/mac/editundo.png
Binary files differ
diff --git a/demos/textedit/images/mac/exportpdf.png b/demos/textedit/images/mac/exportpdf.png
new file mode 100644
index 0000000..ebb44e6
--- /dev/null
+++ b/demos/textedit/images/mac/exportpdf.png
Binary files differ
diff --git a/demos/textedit/images/mac/filenew.png b/demos/textedit/images/mac/filenew.png
new file mode 100644
index 0000000..d3882c7
--- /dev/null
+++ b/demos/textedit/images/mac/filenew.png
Binary files differ
diff --git a/demos/textedit/images/mac/fileopen.png b/demos/textedit/images/mac/fileopen.png
new file mode 100644
index 0000000..fc06c5e
--- /dev/null
+++ b/demos/textedit/images/mac/fileopen.png
Binary files differ
diff --git a/demos/textedit/images/mac/fileprint.png b/demos/textedit/images/mac/fileprint.png
new file mode 100644
index 0000000..10ca56c
--- /dev/null
+++ b/demos/textedit/images/mac/fileprint.png
Binary files differ
diff --git a/demos/textedit/images/mac/filesave.png b/demos/textedit/images/mac/filesave.png
new file mode 100644
index 0000000..b41ecf5
--- /dev/null
+++ b/demos/textedit/images/mac/filesave.png
Binary files differ
diff --git a/demos/textedit/images/mac/textbold.png b/demos/textedit/images/mac/textbold.png
new file mode 100644
index 0000000..38400bd
--- /dev/null
+++ b/demos/textedit/images/mac/textbold.png
Binary files differ
diff --git a/demos/textedit/images/mac/textcenter.png b/demos/textedit/images/mac/textcenter.png
new file mode 100644
index 0000000..2ef5b2e
--- /dev/null
+++ b/demos/textedit/images/mac/textcenter.png
Binary files differ
diff --git a/demos/textedit/images/mac/textitalic.png b/demos/textedit/images/mac/textitalic.png
new file mode 100644
index 0000000..0170ee2
--- /dev/null
+++ b/demos/textedit/images/mac/textitalic.png
Binary files differ
diff --git a/demos/textedit/images/mac/textjustify.png b/demos/textedit/images/mac/textjustify.png
new file mode 100644
index 0000000..39cd6c1
--- /dev/null
+++ b/demos/textedit/images/mac/textjustify.png
Binary files differ
diff --git a/demos/textedit/images/mac/textleft.png b/demos/textedit/images/mac/textleft.png
new file mode 100644
index 0000000..83a66d5
--- /dev/null
+++ b/demos/textedit/images/mac/textleft.png
Binary files differ
diff --git a/demos/textedit/images/mac/textright.png b/demos/textedit/images/mac/textright.png
new file mode 100644
index 0000000..e7c0464
--- /dev/null
+++ b/demos/textedit/images/mac/textright.png
Binary files differ
diff --git a/demos/textedit/images/mac/textunder.png b/demos/textedit/images/mac/textunder.png
new file mode 100644
index 0000000..968bac5
--- /dev/null
+++ b/demos/textedit/images/mac/textunder.png
Binary files differ
diff --git a/demos/textedit/images/mac/zoomin.png b/demos/textedit/images/mac/zoomin.png
new file mode 100644
index 0000000..d46f5af
--- /dev/null
+++ b/demos/textedit/images/mac/zoomin.png
Binary files differ
diff --git a/demos/textedit/images/mac/zoomout.png b/demos/textedit/images/mac/zoomout.png
new file mode 100644
index 0000000..4632656
--- /dev/null
+++ b/demos/textedit/images/mac/zoomout.png
Binary files differ
diff --git a/demos/textedit/images/win/editcopy.png b/demos/textedit/images/win/editcopy.png
new file mode 100644
index 0000000..1121b47
--- /dev/null
+++ b/demos/textedit/images/win/editcopy.png
Binary files differ
diff --git a/demos/textedit/images/win/editcut.png b/demos/textedit/images/win/editcut.png
new file mode 100644
index 0000000..38e55f7
--- /dev/null
+++ b/demos/textedit/images/win/editcut.png
Binary files differ
diff --git a/demos/textedit/images/win/editpaste.png b/demos/textedit/images/win/editpaste.png
new file mode 100644
index 0000000..ffab15a
--- /dev/null
+++ b/demos/textedit/images/win/editpaste.png
Binary files differ
diff --git a/demos/textedit/images/win/editredo.png b/demos/textedit/images/win/editredo.png
new file mode 100644
index 0000000..9d679fe
--- /dev/null
+++ b/demos/textedit/images/win/editredo.png
Binary files differ
diff --git a/demos/textedit/images/win/editundo.png b/demos/textedit/images/win/editundo.png
new file mode 100644
index 0000000..eee23d2
--- /dev/null
+++ b/demos/textedit/images/win/editundo.png
Binary files differ
diff --git a/demos/textedit/images/win/exportpdf.png b/demos/textedit/images/win/exportpdf.png
new file mode 100644
index 0000000..eef5132
--- /dev/null
+++ b/demos/textedit/images/win/exportpdf.png
Binary files differ
diff --git a/demos/textedit/images/win/filenew.png b/demos/textedit/images/win/filenew.png
new file mode 100644
index 0000000..af5d122
--- /dev/null
+++ b/demos/textedit/images/win/filenew.png
Binary files differ
diff --git a/demos/textedit/images/win/fileopen.png b/demos/textedit/images/win/fileopen.png
new file mode 100644
index 0000000..fc6f17e
--- /dev/null
+++ b/demos/textedit/images/win/fileopen.png
Binary files differ
diff --git a/demos/textedit/images/win/fileprint.png b/demos/textedit/images/win/fileprint.png
new file mode 100644
index 0000000..ba7c02d
--- /dev/null
+++ b/demos/textedit/images/win/fileprint.png
Binary files differ
diff --git a/demos/textedit/images/win/filesave.png b/demos/textedit/images/win/filesave.png
new file mode 100644
index 0000000..8feec99
--- /dev/null
+++ b/demos/textedit/images/win/filesave.png
Binary files differ
diff --git a/demos/textedit/images/win/textbold.png b/demos/textedit/images/win/textbold.png
new file mode 100644
index 0000000..9cbc713
--- /dev/null
+++ b/demos/textedit/images/win/textbold.png
Binary files differ
diff --git a/demos/textedit/images/win/textcenter.png b/demos/textedit/images/win/textcenter.png
new file mode 100644
index 0000000..11efb4b
--- /dev/null
+++ b/demos/textedit/images/win/textcenter.png
Binary files differ
diff --git a/demos/textedit/images/win/textitalic.png b/demos/textedit/images/win/textitalic.png
new file mode 100644
index 0000000..b30ce14
--- /dev/null
+++ b/demos/textedit/images/win/textitalic.png
Binary files differ
diff --git a/demos/textedit/images/win/textjustify.png b/demos/textedit/images/win/textjustify.png
new file mode 100644
index 0000000..9de0c88
--- /dev/null
+++ b/demos/textedit/images/win/textjustify.png
Binary files differ
diff --git a/demos/textedit/images/win/textleft.png b/demos/textedit/images/win/textleft.png
new file mode 100644
index 0000000..16f80bc
--- /dev/null
+++ b/demos/textedit/images/win/textleft.png
Binary files differ
diff --git a/demos/textedit/images/win/textright.png b/demos/textedit/images/win/textright.png
new file mode 100644
index 0000000..16872df
--- /dev/null
+++ b/demos/textedit/images/win/textright.png
Binary files differ
diff --git a/demos/textedit/images/win/textunder.png b/demos/textedit/images/win/textunder.png
new file mode 100644
index 0000000..c72eff5
--- /dev/null
+++ b/demos/textedit/images/win/textunder.png
Binary files differ
diff --git a/demos/textedit/images/win/zoomin.png b/demos/textedit/images/win/zoomin.png
new file mode 100644
index 0000000..2e586fc
--- /dev/null
+++ b/demos/textedit/images/win/zoomin.png
Binary files differ
diff --git a/demos/textedit/images/win/zoomout.png b/demos/textedit/images/win/zoomout.png
new file mode 100644
index 0000000..a736d39
--- /dev/null
+++ b/demos/textedit/images/win/zoomout.png
Binary files differ
diff --git a/demos/textedit/main.cpp b/demos/textedit/main.cpp
new file mode 100644
index 0000000..fa38ecb
--- /dev/null
+++ b/demos/textedit/main.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "textedit.h"
+#include <QApplication>
+
+int main( int argc, char ** argv )
+{
+ Q_INIT_RESOURCE(textedit);
+
+ QApplication a( argc, argv );
+ TextEdit mw;
+ mw.resize( 700, 800 );
+ mw.show();
+ return a.exec();
+}
diff --git a/demos/textedit/textedit.cpp b/demos/textedit/textedit.cpp
new file mode 100644
index 0000000..7350a42
--- /dev/null
+++ b/demos/textedit/textedit.cpp
@@ -0,0 +1,694 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "textedit.h"
+
+#include <QAction>
+#include <QApplication>
+#include <QClipboard>
+#include <QColorDialog>
+#include <QComboBox>
+#include <QFontComboBox>
+#include <QFile>
+#include <QFileDialog>
+#include <QFileInfo>
+#include <QFontDatabase>
+#include <QMenu>
+#include <QMenuBar>
+#include <QPrintDialog>
+#include <QPrinter>
+#include <QTextCodec>
+#include <QTextEdit>
+#include <QToolBar>
+#include <QTextCursor>
+#include <QTextDocumentWriter>
+#include <QTextList>
+#include <QtDebug>
+#include <QCloseEvent>
+#include <QMessageBox>
+#include <QPrintPreviewDialog>
+
+#ifdef Q_WS_MAC
+const QString rsrcPath = ":/images/mac";
+#else
+const QString rsrcPath = ":/images/win";
+#endif
+
+TextEdit::TextEdit(QWidget *parent)
+ : QMainWindow(parent)
+{
+ setupFileActions();
+ setupEditActions();
+ setupTextActions();
+
+ {
+ QMenu *helpMenu = new QMenu(tr("Help"), this);
+ menuBar()->addMenu(helpMenu);
+ helpMenu->addAction(tr("About"), this, SLOT(about()));
+ helpMenu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt()));
+ }
+
+ textEdit = new QTextEdit(this);
+ connect(textEdit, SIGNAL(currentCharFormatChanged(const QTextCharFormat &)),
+ this, SLOT(currentCharFormatChanged(const QTextCharFormat &)));
+ connect(textEdit, SIGNAL(cursorPositionChanged()),
+ this, SLOT(cursorPositionChanged()));
+
+ setCentralWidget(textEdit);
+ textEdit->setFocus();
+ setCurrentFileName(QString());
+
+ fontChanged(textEdit->font());
+ colorChanged(textEdit->textColor());
+ alignmentChanged(textEdit->alignment());
+
+ connect(textEdit->document(), SIGNAL(modificationChanged(bool)),
+ actionSave, SLOT(setEnabled(bool)));
+ connect(textEdit->document(), SIGNAL(modificationChanged(bool)),
+ this, SLOT(setWindowModified(bool)));
+ connect(textEdit->document(), SIGNAL(undoAvailable(bool)),
+ actionUndo, SLOT(setEnabled(bool)));
+ connect(textEdit->document(), SIGNAL(redoAvailable(bool)),
+ actionRedo, SLOT(setEnabled(bool)));
+
+ setWindowModified(textEdit->document()->isModified());
+ actionSave->setEnabled(textEdit->document()->isModified());
+ actionUndo->setEnabled(textEdit->document()->isUndoAvailable());
+ actionRedo->setEnabled(textEdit->document()->isRedoAvailable());
+
+ connect(actionUndo, SIGNAL(triggered()), textEdit, SLOT(undo()));
+ connect(actionRedo, SIGNAL(triggered()), textEdit, SLOT(redo()));
+
+ actionCut->setEnabled(false);
+ actionCopy->setEnabled(false);
+
+ connect(actionCut, SIGNAL(triggered()), textEdit, SLOT(cut()));
+ connect(actionCopy, SIGNAL(triggered()), textEdit, SLOT(copy()));
+ connect(actionPaste, SIGNAL(triggered()), textEdit, SLOT(paste()));
+
+ connect(textEdit, SIGNAL(copyAvailable(bool)), actionCut, SLOT(setEnabled(bool)));
+ connect(textEdit, SIGNAL(copyAvailable(bool)), actionCopy, SLOT(setEnabled(bool)));
+
+#ifndef QT_NO_CLIPBOARD
+ connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged()));
+#endif
+
+ QString initialFile = ":/example.html";
+ const QStringList args = QCoreApplication::arguments();
+ if (args.count() == 2)
+ initialFile = args.at(1);
+
+ if (!load(initialFile))
+ fileNew();
+}
+
+void TextEdit::closeEvent(QCloseEvent *e)
+{
+ if (maybeSave())
+ e->accept();
+ else
+ e->ignore();
+}
+
+void TextEdit::setupFileActions()
+{
+ QToolBar *tb = new QToolBar(this);
+ tb->setWindowTitle(tr("File Actions"));
+ addToolBar(tb);
+
+ QMenu *menu = new QMenu(tr("&File"), this);
+ menuBar()->addMenu(menu);
+
+ QAction *a;
+
+ a = new QAction(QIcon(rsrcPath + "/filenew.png"), tr("&New"), this);
+ a->setShortcut(QKeySequence::New);
+ connect(a, SIGNAL(triggered()), this, SLOT(fileNew()));
+ tb->addAction(a);
+ menu->addAction(a);
+
+ a = new QAction(QIcon(rsrcPath + "/fileopen.png"), tr("&Open..."), this);
+ a->setShortcut(QKeySequence::Open);
+ connect(a, SIGNAL(triggered()), this, SLOT(fileOpen()));
+ tb->addAction(a);
+ menu->addAction(a);
+
+ menu->addSeparator();
+
+ actionSave = a = new QAction(QIcon(rsrcPath + "/filesave.png"), tr("&Save"), this);
+ a->setShortcut(QKeySequence::Save);
+ connect(a, SIGNAL(triggered()), this, SLOT(fileSave()));
+ a->setEnabled(false);
+ tb->addAction(a);
+ menu->addAction(a);
+
+ a = new QAction(tr("Save &As..."), this);
+ connect(a, SIGNAL(triggered()), this, SLOT(fileSaveAs()));
+ menu->addAction(a);
+ menu->addSeparator();
+
+#ifndef QT_NO_PRINTER
+ a = new QAction(QIcon(rsrcPath + "/fileprint.png"), tr("&Print..."), this);
+ a->setShortcut(QKeySequence::Print);
+ connect(a, SIGNAL(triggered()), this, SLOT(filePrint()));
+ tb->addAction(a);
+ menu->addAction(a);
+
+ a = new QAction(QIcon(rsrcPath + "/fileprint.png"), tr("Print Preview..."), this);
+ connect(a, SIGNAL(triggered()), this, SLOT(filePrintPreview()));
+ menu->addAction(a);
+
+ a = new QAction(QIcon(rsrcPath + "/exportpdf.png"), tr("&Export PDF..."), this);
+ a->setShortcut(Qt::CTRL + Qt::Key_D);
+ connect(a, SIGNAL(triggered()), this, SLOT(filePrintPdf()));
+ tb->addAction(a);
+ menu->addAction(a);
+
+ menu->addSeparator();
+#endif
+
+ a = new QAction(tr("&Quit"), this);
+ a->setShortcut(Qt::CTRL + Qt::Key_Q);
+ connect(a, SIGNAL(triggered()), this, SLOT(close()));
+ menu->addAction(a);
+}
+
+void TextEdit::setupEditActions()
+{
+ QToolBar *tb = new QToolBar(this);
+ tb->setWindowTitle(tr("Edit Actions"));
+ addToolBar(tb);
+
+ QMenu *menu = new QMenu(tr("&Edit"), this);
+ menuBar()->addMenu(menu);
+
+ QAction *a;
+ a = actionUndo = new QAction(QIcon(rsrcPath + "/editundo.png"), tr("&Undo"), this);
+ a->setShortcut(QKeySequence::Undo);
+ tb->addAction(a);
+ menu->addAction(a);
+ a = actionRedo = new QAction(QIcon(rsrcPath + "/editredo.png"), tr("&Redo"), this);
+ a->setShortcut(QKeySequence::Redo);
+ tb->addAction(a);
+ menu->addAction(a);
+ menu->addSeparator();
+ a = actionCut = new QAction(QIcon(rsrcPath + "/editcut.png"), tr("Cu&t"), this);
+ a->setShortcut(QKeySequence::Cut);
+ tb->addAction(a);
+ menu->addAction(a);
+ a = actionCopy = new QAction(QIcon(rsrcPath + "/editcopy.png"), tr("&Copy"), this);
+ a->setShortcut(QKeySequence::Copy);
+ tb->addAction(a);
+ menu->addAction(a);
+ a = actionPaste = new QAction(QIcon(rsrcPath + "/editpaste.png"), tr("&Paste"), this);
+ a->setShortcut(QKeySequence::Paste);
+ tb->addAction(a);
+ menu->addAction(a);
+#ifndef QT_NO_CLIPBOARD
+ actionPaste->setEnabled(!QApplication::clipboard()->text().isEmpty());
+#endif
+}
+
+void TextEdit::setupTextActions()
+{
+ QToolBar *tb = new QToolBar(this);
+ tb->setWindowTitle(tr("Format Actions"));
+ addToolBar(tb);
+
+ QMenu *menu = new QMenu(tr("F&ormat"), this);
+ menuBar()->addMenu(menu);
+
+ actionTextBold = new QAction(QIcon(rsrcPath + "/textbold.png"), tr("&Bold"), this);
+ actionTextBold->setShortcut(Qt::CTRL + Qt::Key_B);
+ QFont bold;
+ bold.setBold(true);
+ actionTextBold->setFont(bold);
+ connect(actionTextBold, SIGNAL(triggered()), this, SLOT(textBold()));
+ tb->addAction(actionTextBold);
+ menu->addAction(actionTextBold);
+ actionTextBold->setCheckable(true);
+
+ actionTextItalic = new QAction(QIcon(rsrcPath + "/textitalic.png"), tr("&Italic"), this);
+ actionTextItalic->setShortcut(Qt::CTRL + Qt::Key_I);
+ QFont italic;
+ italic.setItalic(true);
+ actionTextItalic->setFont(italic);
+ connect(actionTextItalic, SIGNAL(triggered()), this, SLOT(textItalic()));
+ tb->addAction(actionTextItalic);
+ menu->addAction(actionTextItalic);
+ actionTextItalic->setCheckable(true);
+
+ actionTextUnderline = new QAction(QIcon(rsrcPath + "/textunder.png"), tr("&Underline"), this);
+ actionTextUnderline->setShortcut(Qt::CTRL + Qt::Key_U);
+ QFont underline;
+ underline.setUnderline(true);
+ actionTextUnderline->setFont(underline);
+ connect(actionTextUnderline, SIGNAL(triggered()), this, SLOT(textUnderline()));
+ tb->addAction(actionTextUnderline);
+ menu->addAction(actionTextUnderline);
+ actionTextUnderline->setCheckable(true);
+
+ menu->addSeparator();
+
+ QActionGroup *grp = new QActionGroup(this);
+ connect(grp, SIGNAL(triggered(QAction *)), this, SLOT(textAlign(QAction *)));
+
+ // Make sure the alignLeft is always left of the alignRight
+ if (QApplication::isLeftToRight()) {
+ actionAlignLeft = new QAction(QIcon(rsrcPath + "/textleft.png"), tr("&Left"), grp);
+ actionAlignCenter = new QAction(QIcon(rsrcPath + "/textcenter.png"), tr("C&enter"), grp);
+ actionAlignRight = new QAction(QIcon(rsrcPath + "/textright.png"), tr("&Right"), grp);
+ } else {
+ actionAlignRight = new QAction(QIcon(rsrcPath + "/textright.png"), tr("&Right"), grp);
+ actionAlignCenter = new QAction(QIcon(rsrcPath + "/textcenter.png"), tr("C&enter"), grp);
+ actionAlignLeft = new QAction(QIcon(rsrcPath + "/textleft.png"), tr("&Left"), grp);
+ }
+ actionAlignJustify = new QAction(QIcon(rsrcPath + "/textjustify.png"), tr("&Justify"), grp);
+
+ actionAlignLeft->setShortcut(Qt::CTRL + Qt::Key_L);
+ actionAlignLeft->setCheckable(true);
+ actionAlignCenter->setShortcut(Qt::CTRL + Qt::Key_E);
+ actionAlignCenter->setCheckable(true);
+ actionAlignRight->setShortcut(Qt::CTRL + Qt::Key_R);
+ actionAlignRight->setCheckable(true);
+ actionAlignJustify->setShortcut(Qt::CTRL + Qt::Key_J);
+ actionAlignJustify->setCheckable(true);
+
+ tb->addActions(grp->actions());
+ menu->addActions(grp->actions());
+
+ menu->addSeparator();
+
+ QPixmap pix(16, 16);
+ pix.fill(Qt::black);
+ actionTextColor = new QAction(pix, tr("&Color..."), this);
+ connect(actionTextColor, SIGNAL(triggered()), this, SLOT(textColor()));
+ tb->addAction(actionTextColor);
+ menu->addAction(actionTextColor);
+
+
+ tb = new QToolBar(this);
+ tb->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea);
+ tb->setWindowTitle(tr("Format Actions"));
+ addToolBarBreak(Qt::TopToolBarArea);
+ addToolBar(tb);
+
+ comboStyle = new QComboBox(tb);
+ tb->addWidget(comboStyle);
+ comboStyle->addItem("Standard");
+ comboStyle->addItem("Bullet List (Disc)");
+ comboStyle->addItem("Bullet List (Circle)");
+ comboStyle->addItem("Bullet List (Square)");
+ comboStyle->addItem("Ordered List (Decimal)");
+ comboStyle->addItem("Ordered List (Alpha lower)");
+ comboStyle->addItem("Ordered List (Alpha upper)");
+ connect(comboStyle, SIGNAL(activated(int)),
+ this, SLOT(textStyle(int)));
+
+ comboFont = new QFontComboBox(tb);
+ tb->addWidget(comboFont);
+ connect(comboFont, SIGNAL(activated(const QString &)),
+ this, SLOT(textFamily(const QString &)));
+
+ comboSize = new QComboBox(tb);
+ comboSize->setObjectName("comboSize");
+ tb->addWidget(comboSize);
+ comboSize->setEditable(true);
+
+ QFontDatabase db;
+ foreach(int size, db.standardSizes())
+ comboSize->addItem(QString::number(size));
+
+ connect(comboSize, SIGNAL(activated(const QString &)),
+ this, SLOT(textSize(const QString &)));
+ comboSize->setCurrentIndex(comboSize->findText(QString::number(QApplication::font()
+ .pointSize())));
+}
+
+bool TextEdit::load(const QString &f)
+{
+ if (!QFile::exists(f))
+ return false;
+ QFile file(f);
+ if (!file.open(QFile::ReadOnly))
+ return false;
+
+ QByteArray data = file.readAll();
+ QTextCodec *codec = Qt::codecForHtml(data);
+ QString str = codec->toUnicode(data);
+ if (Qt::mightBeRichText(str)) {
+ textEdit->setHtml(str);
+ } else {
+ str = QString::fromLocal8Bit(data);
+ textEdit->setPlainText(str);
+ }
+
+ setCurrentFileName(f);
+ return true;
+}
+
+bool TextEdit::maybeSave()
+{
+ if (!textEdit->document()->isModified())
+ return true;
+ if (fileName.startsWith(QLatin1String(":/")))
+ return true;
+ QMessageBox::StandardButton ret;
+ ret = QMessageBox::warning(this, tr("Application"),
+ tr("The document has been modified.\n"
+ "Do you want to save your changes?"),
+ QMessageBox::Save | QMessageBox::Discard
+ | QMessageBox::Cancel);
+ if (ret == QMessageBox::Save)
+ return fileSave();
+ else if (ret == QMessageBox::Cancel)
+ return false;
+ return true;
+}
+
+void TextEdit::setCurrentFileName(const QString &fileName)
+{
+ this->fileName = fileName;
+ textEdit->document()->setModified(false);
+
+ QString shownName;
+ if (fileName.isEmpty())
+ shownName = "untitled.txt";
+ else
+ shownName = QFileInfo(fileName).fileName();
+
+ setWindowTitle(tr("%1[*] - %2").arg(shownName).arg(tr("Rich Text")));
+ setWindowModified(false);
+}
+
+void TextEdit::fileNew()
+{
+ if (maybeSave()) {
+ textEdit->clear();
+ setCurrentFileName(QString());
+ }
+}
+
+void TextEdit::fileOpen()
+{
+ QString fn = QFileDialog::getOpenFileName(this, tr("Open File..."),
+ QString(), tr("HTML-Files (*.htm *.html);;All Files (*)"));
+ if (!fn.isEmpty())
+ load(fn);
+}
+
+bool TextEdit::fileSave()
+{
+ if (fileName.isEmpty())
+ return fileSaveAs();
+
+ QTextDocumentWriter writer(fileName);
+ bool success = writer.write(textEdit->document());
+ if (success)
+ textEdit->document()->setModified(false);
+ return success;
+}
+
+bool TextEdit::fileSaveAs()
+{
+ QString fn = QFileDialog::getSaveFileName(this, tr("Save as..."),
+ QString(), tr("ODF files (*.odt);;HTML-Files (*.htm *.html);;All Files (*)"));
+ if (fn.isEmpty())
+ return false;
+ if (! (fn.endsWith(".odt", Qt::CaseInsensitive) || fn.endsWith(".htm", Qt::CaseInsensitive) || fn.endsWith(".html", Qt::CaseInsensitive)) )
+ fn += ".odt"; // default
+ setCurrentFileName(fn);
+ return fileSave();
+}
+
+void TextEdit::filePrint()
+{
+#ifndef QT_NO_PRINTER
+ QPrinter printer(QPrinter::HighResolution);
+ QPrintDialog *dlg = new QPrintDialog(&printer, this);
+ if (textEdit->textCursor().hasSelection())
+ dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection);
+ dlg->setWindowTitle(tr("Print Document"));
+ if (dlg->exec() == QDialog::Accepted) {
+ textEdit->print(&printer);
+ }
+ delete dlg;
+#endif
+}
+
+void TextEdit::filePrintPreview()
+{
+#ifndef QT_NO_PRINTER
+ QPrinter printer(QPrinter::HighResolution);
+ QPrintPreviewDialog preview(&printer, this);
+ connect(&preview, SIGNAL(paintRequested(QPrinter *)), SLOT(printPreview(QPrinter *)));
+ preview.exec();
+#endif
+}
+
+void TextEdit::printPreview(QPrinter *printer)
+{
+#ifdef QT_NO_PRINTER
+ Q_UNUSED(printer);
+#else
+ textEdit->print(printer);
+#endif
+}
+
+
+void TextEdit::filePrintPdf()
+{
+#ifndef QT_NO_PRINTER
+//! [0]
+ QString fileName = QFileDialog::getSaveFileName(this, "Export PDF",
+ QString(), "*.pdf");
+ if (!fileName.isEmpty()) {
+ if (QFileInfo(fileName).suffix().isEmpty())
+ fileName.append(".pdf");
+ QPrinter printer(QPrinter::HighResolution);
+ printer.setOutputFormat(QPrinter::PdfFormat);
+ printer.setOutputFileName(fileName);
+ textEdit->document()->print(&printer);
+ }
+//! [0]
+#endif
+}
+
+void TextEdit::textBold()
+{
+ QTextCharFormat fmt;
+ fmt.setFontWeight(actionTextBold->isChecked() ? QFont::Bold : QFont::Normal);
+ mergeFormatOnWordOrSelection(fmt);
+}
+
+void TextEdit::textUnderline()
+{
+ QTextCharFormat fmt;
+ fmt.setFontUnderline(actionTextUnderline->isChecked());
+ mergeFormatOnWordOrSelection(fmt);
+}
+
+void TextEdit::textItalic()
+{
+ QTextCharFormat fmt;
+ fmt.setFontItalic(actionTextItalic->isChecked());
+ mergeFormatOnWordOrSelection(fmt);
+}
+
+void TextEdit::textFamily(const QString &f)
+{
+ QTextCharFormat fmt;
+ fmt.setFontFamily(f);
+ mergeFormatOnWordOrSelection(fmt);
+}
+
+void TextEdit::textSize(const QString &p)
+{
+ qreal pointSize = p.toFloat();
+ if (p.toFloat() > 0) {
+ QTextCharFormat fmt;
+ fmt.setFontPointSize(pointSize);
+ mergeFormatOnWordOrSelection(fmt);
+ }
+}
+
+void TextEdit::textStyle(int styleIndex)
+{
+ QTextCursor cursor = textEdit->textCursor();
+
+ if (styleIndex != 0) {
+ QTextListFormat::Style style = QTextListFormat::ListDisc;
+
+ switch (styleIndex) {
+ default:
+ case 1:
+ style = QTextListFormat::ListDisc;
+ break;
+ case 2:
+ style = QTextListFormat::ListCircle;
+ break;
+ case 3:
+ style = QTextListFormat::ListSquare;
+ break;
+ case 4:
+ style = QTextListFormat::ListDecimal;
+ break;
+ case 5:
+ style = QTextListFormat::ListLowerAlpha;
+ break;
+ case 6:
+ style = QTextListFormat::ListUpperAlpha;
+ break;
+ }
+
+ cursor.beginEditBlock();
+
+ QTextBlockFormat blockFmt = cursor.blockFormat();
+
+ QTextListFormat listFmt;
+
+ if (cursor.currentList()) {
+ listFmt = cursor.currentList()->format();
+ } else {
+ listFmt.setIndent(blockFmt.indent() + 1);
+ blockFmt.setIndent(0);
+ cursor.setBlockFormat(blockFmt);
+ }
+
+ listFmt.setStyle(style);
+
+ cursor.createList(listFmt);
+
+ cursor.endEditBlock();
+ } else {
+ // ####
+ QTextBlockFormat bfmt;
+ bfmt.setObjectIndex(-1);
+ cursor.mergeBlockFormat(bfmt);
+ }
+}
+
+void TextEdit::textColor()
+{
+ QColor col = QColorDialog::getColor(textEdit->textColor(), this);
+ if (!col.isValid())
+ return;
+ QTextCharFormat fmt;
+ fmt.setForeground(col);
+ mergeFormatOnWordOrSelection(fmt);
+ colorChanged(col);
+}
+
+void TextEdit::textAlign(QAction *a)
+{
+ if (a == actionAlignLeft)
+ textEdit->setAlignment(Qt::AlignLeft | Qt::AlignAbsolute);
+ else if (a == actionAlignCenter)
+ textEdit->setAlignment(Qt::AlignHCenter);
+ else if (a == actionAlignRight)
+ textEdit->setAlignment(Qt::AlignRight | Qt::AlignAbsolute);
+ else if (a == actionAlignJustify)
+ textEdit->setAlignment(Qt::AlignJustify);
+}
+
+void TextEdit::currentCharFormatChanged(const QTextCharFormat &format)
+{
+ fontChanged(format.font());
+ colorChanged(format.foreground().color());
+}
+
+void TextEdit::cursorPositionChanged()
+{
+ alignmentChanged(textEdit->alignment());
+}
+
+void TextEdit::clipboardDataChanged()
+{
+#ifndef QT_NO_CLIPBOARD
+ actionPaste->setEnabled(!QApplication::clipboard()->text().isEmpty());
+#endif
+}
+
+void TextEdit::about()
+{
+ QMessageBox::about(this, tr("About"), tr("This example demonstrates Qt's "
+ "rich text editing facilities in action, providing an example "
+ "document for you to experiment with."));
+}
+
+void TextEdit::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
+{
+ QTextCursor cursor = textEdit->textCursor();
+ if (!cursor.hasSelection())
+ cursor.select(QTextCursor::WordUnderCursor);
+ cursor.mergeCharFormat(format);
+ textEdit->mergeCurrentCharFormat(format);
+}
+
+void TextEdit::fontChanged(const QFont &f)
+{
+ comboFont->setCurrentIndex(comboFont->findText(QFontInfo(f).family()));
+ comboSize->setCurrentIndex(comboSize->findText(QString::number(f.pointSize())));
+ actionTextBold->setChecked(f.bold());
+ actionTextItalic->setChecked(f.italic());
+ actionTextUnderline->setChecked(f.underline());
+}
+
+void TextEdit::colorChanged(const QColor &c)
+{
+ QPixmap pix(16, 16);
+ pix.fill(c);
+ actionTextColor->setIcon(pix);
+}
+
+void TextEdit::alignmentChanged(Qt::Alignment a)
+{
+ if (a & Qt::AlignLeft) {
+ actionAlignLeft->setChecked(true);
+ } else if (a & Qt::AlignHCenter) {
+ actionAlignCenter->setChecked(true);
+ } else if (a & Qt::AlignRight) {
+ actionAlignRight->setChecked(true);
+ } else if (a & Qt::AlignJustify) {
+ actionAlignJustify->setChecked(true);
+ }
+}
+
diff --git a/demos/textedit/textedit.doc b/demos/textedit/textedit.doc
new file mode 100644
index 0000000..53279b9
--- /dev/null
+++ b/demos/textedit/textedit.doc
@@ -0,0 +1,18 @@
+/*! \page textedit-example.html
+
+ \ingroup examples
+ \title Text Edit Example
+
+ This example displays a text editor with the user interface written
+ in pure C++.
+
+ A similar example which uses \link designer-manual.book Qt
+ Designer\endlink to produce the user interface is in the \link
+ designer-manual.book Qt Designer manual\endlink.
+
+
+ See \c{$QTDIR/examples/textedit} for the source code.
+
+*/
+
+
diff --git a/demos/textedit/textedit.h b/demos/textedit/textedit.h
new file mode 100644
index 0000000..1fb09f9
--- /dev/null
+++ b/demos/textedit/textedit.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXTEDIT_H
+#define TEXTEDIT_H
+
+#include <QMainWindow>
+#include <QMap>
+#include <QPointer>
+
+QT_FORWARD_DECLARE_CLASS(QAction)
+QT_FORWARD_DECLARE_CLASS(QComboBox)
+QT_FORWARD_DECLARE_CLASS(QFontComboBox)
+QT_FORWARD_DECLARE_CLASS(QTextEdit)
+QT_FORWARD_DECLARE_CLASS(QTextCharFormat)
+QT_FORWARD_DECLARE_CLASS(QMenu)
+
+class TextEdit : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ TextEdit(QWidget *parent = 0);
+
+protected:
+ virtual void closeEvent(QCloseEvent *e);
+
+private:
+ void setupFileActions();
+ void setupEditActions();
+ void setupTextActions();
+ bool load(const QString &f);
+ bool maybeSave();
+ void setCurrentFileName(const QString &fileName);
+
+private slots:
+ void fileNew();
+ void fileOpen();
+ bool fileSave();
+ bool fileSaveAs();
+ void filePrint();
+ void filePrintPreview();
+ void filePrintPdf();
+
+ void textBold();
+ void textUnderline();
+ void textItalic();
+ void textFamily(const QString &f);
+ void textSize(const QString &p);
+ void textStyle(int styleIndex);
+ void textColor();
+ void textAlign(QAction *a);
+
+ void currentCharFormatChanged(const QTextCharFormat &format);
+ void cursorPositionChanged();
+
+ void clipboardDataChanged();
+ void about();
+ void printPreview(QPrinter *);
+
+private:
+ void mergeFormatOnWordOrSelection(const QTextCharFormat &format);
+ void fontChanged(const QFont &f);
+ void colorChanged(const QColor &c);
+ void alignmentChanged(Qt::Alignment a);
+
+ QAction *actionSave,
+ *actionTextBold,
+ *actionTextUnderline,
+ *actionTextItalic,
+ *actionTextColor,
+ *actionAlignLeft,
+ *actionAlignCenter,
+ *actionAlignRight,
+ *actionAlignJustify,
+ *actionUndo,
+ *actionRedo,
+ *actionCut,
+ *actionCopy,
+ *actionPaste;
+
+ QComboBox *comboStyle;
+ QFontComboBox *comboFont;
+ QComboBox *comboSize;
+
+ QToolBar *tb;
+ QString fileName;
+ QTextEdit *textEdit;
+};
+
+#endif
diff --git a/demos/textedit/textedit.pro b/demos/textedit/textedit.pro
new file mode 100644
index 0000000..6f15e70
--- /dev/null
+++ b/demos/textedit/textedit.pro
@@ -0,0 +1,23 @@
+TEMPLATE = app
+TARGET = textedit
+
+CONFIG += qt warn_on
+
+HEADERS = textedit.h
+SOURCES = textedit.cpp \
+ main.cpp
+
+RESOURCES += textedit.qrc
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/textedit
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.html *.doc images
+sources.path = $$[QT_INSTALL_DEMOS]/textedit
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
diff --git a/demos/textedit/textedit.qrc b/demos/textedit/textedit.qrc
new file mode 100644
index 0000000..7d6efd7
--- /dev/null
+++ b/demos/textedit/textedit.qrc
@@ -0,0 +1,44 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>images/logo32.png</file>
+ <file>images/mac/editcopy.png</file>
+ <file>images/mac/editcut.png</file>
+ <file>images/mac/editpaste.png</file>
+ <file>images/mac/editredo.png</file>
+ <file>images/mac/editundo.png</file>
+ <file>images/mac/exportpdf.png</file>
+ <file>images/mac/filenew.png</file>
+ <file>images/mac/fileopen.png</file>
+ <file>images/mac/fileprint.png</file>
+ <file>images/mac/filesave.png</file>
+ <file>images/mac/textbold.png</file>
+ <file>images/mac/textcenter.png</file>
+ <file>images/mac/textitalic.png</file>
+ <file>images/mac/textjustify.png</file>
+ <file>images/mac/textleft.png</file>
+ <file>images/mac/textright.png</file>
+ <file>images/mac/textunder.png</file>
+ <file>images/mac/zoomin.png</file>
+ <file>images/mac/zoomout.png</file>
+ <file>images/win/editcopy.png</file>
+ <file>images/win/editcut.png</file>
+ <file>images/win/editpaste.png</file>
+ <file>images/win/editredo.png</file>
+ <file>images/win/editundo.png</file>
+ <file>images/win/exportpdf.png</file>
+ <file>images/win/filenew.png</file>
+ <file>images/win/fileopen.png</file>
+ <file>images/win/fileprint.png</file>
+ <file>images/win/filesave.png</file>
+ <file>images/win/textbold.png</file>
+ <file>images/win/textcenter.png</file>
+ <file>images/win/textitalic.png</file>
+ <file>images/win/textjustify.png</file>
+ <file>images/win/textleft.png</file>
+ <file>images/win/textright.png</file>
+ <file>images/win/textunder.png</file>
+ <file>images/win/zoomin.png</file>
+ <file>images/win/zoomout.png</file>
+ <file>example.html</file>
+</qresource>
+</RCC>
diff --git a/demos/undo/commands.cpp b/demos/undo/commands.cpp
new file mode 100644
index 0000000..4802e34
--- /dev/null
+++ b/demos/undo/commands.cpp
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "commands.h"
+
+static const int setShapeRectCommandId = 1;
+static const int setShapeColorCommandId = 2;
+
+/******************************************************************************
+** AddShapeCommand
+*/
+
+AddShapeCommand::AddShapeCommand(Document *doc, const Shape &shape, QUndoCommand *parent)
+ : QUndoCommand(parent)
+{
+ m_doc = doc;
+ m_shape = shape;
+}
+
+void AddShapeCommand::undo()
+{
+ m_doc->deleteShape(m_shapeName);
+}
+
+void AddShapeCommand::redo()
+{
+ // A shape only gets a name when it is inserted into a document
+ m_shapeName = m_doc->addShape(m_shape);
+ setText(QObject::tr("Add %1").arg(m_shapeName));
+}
+
+/******************************************************************************
+** RemoveShapeCommand
+*/
+
+RemoveShapeCommand::RemoveShapeCommand(Document *doc, const QString &shapeName,
+ QUndoCommand *parent)
+ : QUndoCommand(parent)
+{
+ setText(QObject::tr("Remove %1").arg(shapeName));
+ m_doc = doc;
+ m_shape = doc->shape(shapeName);
+ m_shapeName = shapeName;
+}
+
+void RemoveShapeCommand::undo()
+{
+ m_shapeName = m_doc->addShape(m_shape);
+}
+
+void RemoveShapeCommand::redo()
+{
+ m_doc->deleteShape(m_shapeName);
+}
+
+/******************************************************************************
+** SetShapeColorCommand
+*/
+
+SetShapeColorCommand::SetShapeColorCommand(Document *doc, const QString &shapeName,
+ const QColor &color, QUndoCommand *parent)
+ : QUndoCommand(parent)
+{
+ setText(QObject::tr("Set %1's color").arg(shapeName));
+
+ m_doc = doc;
+ m_shapeName = shapeName;
+ m_oldColor = doc->shape(shapeName).color();
+ m_newColor = color;
+}
+
+void SetShapeColorCommand::undo()
+{
+ m_doc->setShapeColor(m_shapeName, m_oldColor);
+}
+
+void SetShapeColorCommand::redo()
+{
+ m_doc->setShapeColor(m_shapeName, m_newColor);
+}
+
+bool SetShapeColorCommand::mergeWith(const QUndoCommand *command)
+{
+ if (command->id() != setShapeColorCommandId)
+ return false;
+
+ const SetShapeColorCommand *other = static_cast<const SetShapeColorCommand*>(command);
+ if (m_shapeName != other->m_shapeName)
+ return false;
+
+ m_newColor = other->m_newColor;
+ return true;
+}
+
+int SetShapeColorCommand::id() const
+{
+ return setShapeColorCommandId;
+}
+
+/******************************************************************************
+** SetShapeRectCommand
+*/
+
+SetShapeRectCommand::SetShapeRectCommand(Document *doc, const QString &shapeName,
+ const QRect &rect, QUndoCommand *parent)
+ : QUndoCommand(parent)
+{
+ setText(QObject::tr("Change %1's geometry").arg(shapeName));
+
+ m_doc = doc;
+ m_shapeName = shapeName;
+ m_oldRect = doc->shape(shapeName).rect();
+ m_newRect = rect;
+}
+
+void SetShapeRectCommand::undo()
+{
+ m_doc->setShapeRect(m_shapeName, m_oldRect);
+}
+
+void SetShapeRectCommand::redo()
+{
+ m_doc->setShapeRect(m_shapeName, m_newRect);
+}
+
+bool SetShapeRectCommand::mergeWith(const QUndoCommand *command)
+{
+ if (command->id() != setShapeRectCommandId)
+ return false;
+
+ const SetShapeRectCommand *other = static_cast<const SetShapeRectCommand*>(command);
+ if (m_shapeName != other->m_shapeName)
+ return false;
+
+ m_newRect = other->m_newRect;
+ return true;
+}
+
+int SetShapeRectCommand::id() const
+{
+ return setShapeRectCommandId;
+}
diff --git a/demos/undo/commands.h b/demos/undo/commands.h
new file mode 100644
index 0000000..f98cb6d
--- /dev/null
+++ b/demos/undo/commands.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef COMMANDS_H
+#define COMMANDS_H
+
+#include <QUndoCommand>
+#include "document.h"
+
+class AddShapeCommand : public QUndoCommand
+{
+public:
+ AddShapeCommand(Document *doc, const Shape &shape, QUndoCommand *parent = 0);
+ void undo();
+ void redo();
+
+private:
+ Document *m_doc;
+ Shape m_shape;
+ QString m_shapeName;
+};
+
+class RemoveShapeCommand : public QUndoCommand
+{
+public:
+ RemoveShapeCommand(Document *doc, const QString &shapeName, QUndoCommand *parent = 0);
+ void undo();
+ void redo();
+
+private:
+ Document *m_doc;
+ Shape m_shape;
+ QString m_shapeName;
+};
+
+class SetShapeColorCommand : public QUndoCommand
+{
+public:
+ SetShapeColorCommand(Document *doc, const QString &shapeName, const QColor &color,
+ QUndoCommand *parent = 0);
+
+ void undo();
+ void redo();
+
+ bool mergeWith(const QUndoCommand *command);
+ int id() const;
+
+private:
+ Document *m_doc;
+ QString m_shapeName;
+ QColor m_oldColor;
+ QColor m_newColor;
+};
+
+class SetShapeRectCommand : public QUndoCommand
+{
+public:
+ SetShapeRectCommand(Document *doc, const QString &shapeName, const QRect &rect,
+ QUndoCommand *parent = 0);
+
+ void undo();
+ void redo();
+
+ bool mergeWith(const QUndoCommand *command);
+ int id() const;
+
+private:
+ Document *m_doc;
+ QString m_shapeName;
+ QRect m_oldRect;
+ QRect m_newRect;
+};
+
+#endif // COMMANDS_H
diff --git a/demos/undo/document.cpp b/demos/undo/document.cpp
new file mode 100644
index 0000000..df435fd
--- /dev/null
+++ b/demos/undo/document.cpp
@@ -0,0 +1,445 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qevent.h>
+#include <QPainter>
+#include <QTextStream>
+#include <QUndoStack>
+#include "document.h"
+#include "commands.h"
+
+static const int resizeHandleWidth = 6;
+
+/******************************************************************************
+** Shape
+*/
+
+const QSize Shape::minSize(80, 50);
+
+Shape::Shape(Type type, const QColor &color, const QRect &rect)
+ : m_type(type), m_rect(rect), m_color(color)
+{
+}
+
+Shape::Type Shape::type() const
+{
+ return m_type;
+}
+
+QRect Shape::rect() const
+{
+ return m_rect;
+}
+
+QColor Shape::color() const
+{
+ return m_color;
+}
+
+QString Shape::name() const
+{
+ return m_name;
+}
+
+QRect Shape::resizeHandle() const
+{
+ QPoint br = m_rect.bottomRight();
+ return QRect(br - QPoint(resizeHandleWidth, resizeHandleWidth), br);
+}
+
+QString Shape::typeToString(Type type)
+{
+ QString result;
+
+ switch (type) {
+ case Rectangle:
+ result = QLatin1String("Rectangle");
+ break;
+ case Circle:
+ result = QLatin1String("Circle");
+ break;
+ case Triangle:
+ result = QLatin1String("Triangle");
+ break;
+ }
+
+ return result;
+}
+
+Shape::Type Shape::stringToType(const QString &s, bool *ok)
+{
+ if (ok != 0)
+ *ok = true;
+
+ if (s == QLatin1String("Rectangle"))
+ return Rectangle;
+ if (s == QLatin1String("Circle"))
+ return Circle;
+ if (s == QLatin1String("Triangle"))
+ return Triangle;
+
+ if (ok != 0)
+ *ok = false;
+ return Rectangle;
+}
+
+/******************************************************************************
+** Document
+*/
+
+Document::Document(QWidget *parent)
+ : QWidget(parent), m_currentIndex(-1), m_mousePressIndex(-1), m_resizeHandlePressed(false)
+{
+ m_undoStack = new QUndoStack(this);
+
+ setAutoFillBackground(true);
+ setBackgroundRole(QPalette::Base);
+
+ QPalette pal = palette();
+ pal.setBrush(QPalette::Base, QPixmap(":/icons/background.png"));
+ pal.setColor(QPalette::HighlightedText, Qt::red);
+ setPalette(pal);
+}
+
+QString Document::addShape(const Shape &shape)
+{
+ QString name = Shape::typeToString(shape.type());
+ name = uniqueName(name);
+
+ m_shapeList.append(shape);
+ m_shapeList[m_shapeList.count() - 1].m_name = name;
+ setCurrentShape(m_shapeList.count() - 1);
+
+ return name;
+}
+
+void Document::deleteShape(const QString &shapeName)
+{
+ int index = indexOf(shapeName);
+ if (index == -1)
+ return;
+
+ update(m_shapeList.at(index).rect());
+
+ m_shapeList.removeAt(index);
+
+ if (index <= m_currentIndex) {
+ m_currentIndex = -1;
+ if (index == m_shapeList.count())
+ --index;
+ setCurrentShape(index);
+ }
+}
+
+Shape Document::shape(const QString &shapeName) const
+{
+ int index = indexOf(shapeName);
+ if (index == -1)
+ return Shape();
+ return m_shapeList.at(index);
+}
+
+void Document::setShapeRect(const QString &shapeName, const QRect &rect)
+{
+ int index = indexOf(shapeName);
+ if (index == -1)
+ return;
+
+ Shape &shape = m_shapeList[index];
+
+ update(shape.rect());
+ update(rect);
+
+ shape.m_rect = rect;
+}
+
+void Document::setShapeColor(const QString &shapeName, const QColor &color)
+{
+
+ int index = indexOf(shapeName);
+ if (index == -1)
+ return;
+
+ Shape &shape = m_shapeList[index];
+ shape.m_color = color;
+
+ update(shape.rect());
+}
+
+QUndoStack *Document::undoStack() const
+{
+ return m_undoStack;
+}
+
+bool Document::load(QTextStream &stream)
+{
+ m_shapeList.clear();
+
+ while (!stream.atEnd()) {
+ QString shapeType, shapeName, colorName;
+ int left, top, width, height;
+ stream >> shapeType >> shapeName >> colorName >> left >> top >> width >> height;
+ if (stream.status() != QTextStream::Ok)
+ return false;
+ bool ok;
+ Shape::Type type = Shape::stringToType(shapeType, &ok);
+ if (!ok)
+ return false;
+ QColor color(colorName);
+ if (!color.isValid())
+ return false;
+
+ Shape shape(type);
+ shape.m_name = shapeName;
+ shape.m_color = color;
+ shape.m_rect = QRect(left, top, width, height);
+
+ m_shapeList.append(shape);
+ }
+
+ m_currentIndex = m_shapeList.isEmpty() ? -1 : 0;
+
+ return true;
+}
+
+void Document::save(QTextStream &stream)
+{
+ for (int i = 0; i < m_shapeList.count(); ++i) {
+ const Shape &shape = m_shapeList.at(i);
+ QRect r = shape.rect();
+ stream << Shape::typeToString(shape.type()) << QLatin1Char(' ')
+ << shape.name() << QLatin1Char(' ')
+ << shape.color().name() << QLatin1Char(' ')
+ << r.left() << QLatin1Char(' ')
+ << r.top() << QLatin1Char(' ')
+ << r.width() << QLatin1Char(' ')
+ << r.height();
+ if (i != m_shapeList.count() - 1)
+ stream << QLatin1Char('\n');
+ }
+ m_undoStack->setClean();
+}
+
+QString Document::fileName() const
+{
+ return m_fileName;
+}
+
+void Document::setFileName(const QString &fileName)
+{
+ m_fileName = fileName;
+}
+
+int Document::indexAt(const QPoint &pos) const
+{
+ for (int i = m_shapeList.count() - 1; i >= 0; --i) {
+ if (m_shapeList.at(i).rect().contains(pos))
+ return i;
+ }
+ return -1;
+}
+
+void Document::mousePressEvent(QMouseEvent *event)
+{
+ event->accept();
+ int index = indexAt(event->pos());;
+ if (index != -1) {
+ setCurrentShape(index);
+
+ const Shape &shape = m_shapeList.at(index);
+ m_resizeHandlePressed = shape.resizeHandle().contains(event->pos());
+
+ if (m_resizeHandlePressed)
+ m_mousePressOffset = shape.rect().bottomRight() - event->pos();
+ else
+ m_mousePressOffset = event->pos() - shape.rect().topLeft();
+ }
+ m_mousePressIndex = index;
+}
+
+void Document::mouseReleaseEvent(QMouseEvent *event)
+{
+ event->accept();
+ m_mousePressIndex = -1;
+}
+
+void Document::mouseMoveEvent(QMouseEvent *event)
+{
+ event->accept();
+
+ if (m_mousePressIndex == -1)
+ return;
+
+ const Shape &shape = m_shapeList.at(m_mousePressIndex);
+
+ QRect rect;
+ if (m_resizeHandlePressed) {
+ rect = QRect(shape.rect().topLeft(), event->pos() + m_mousePressOffset);
+ } else {
+ rect = shape.rect();
+ rect.moveTopLeft(event->pos() - m_mousePressOffset);
+ }
+
+ QSize size = rect.size().expandedTo(Shape::minSize);
+ rect.setSize(size);
+
+ m_undoStack->push(new SetShapeRectCommand(this, shape.name(), rect));
+}
+
+static QGradient gradient(const QColor &color, const QRect &rect)
+{
+ QColor c = color;
+ c.setAlpha(160);
+ QLinearGradient result(rect.topLeft(), rect.bottomRight());
+ result.setColorAt(0, c.dark(150));
+ result.setColorAt(0.5, c.light(200));
+ result.setColorAt(1, c.dark(150));
+ return result;
+}
+
+static QPolygon triangle(const QRect &rect)
+{
+ QPolygon result(3);
+ result.setPoint(0, rect.center().x(), rect.top());
+ result.setPoint(1, rect.right(), rect.bottom());
+ result.setPoint(2, rect.left(), rect.bottom());
+ return result;
+}
+
+void Document::paintEvent(QPaintEvent *event)
+{
+ QRegion paintRegion = event->region();
+ QPainter painter(this);
+ QPalette pal = palette();
+
+ for (int i = 0; i < m_shapeList.count(); ++i) {
+ const Shape &shape = m_shapeList.at(i);
+
+ if (!paintRegion.contains(shape.rect()))
+ continue;
+
+ QPen pen = pal.text().color();
+ pen.setWidth(i == m_currentIndex ? 2 : 1);
+ painter.setPen(pen);
+ painter.setBrush(gradient(shape.color(), shape.rect()));
+
+ QRect rect = shape.rect();
+ rect.adjust(1, 1, -resizeHandleWidth/2, -resizeHandleWidth/2);
+
+ // paint the shape
+ switch (shape.type()) {
+ case Shape::Rectangle:
+ painter.drawRect(rect);
+ break;
+ case Shape::Circle:
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.drawEllipse(rect);
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ break;
+ case Shape::Triangle:
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.drawPolygon(triangle(rect));
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ break;
+ }
+
+ // paint the resize handle
+ painter.setPen(pal.text().color());
+ painter.setBrush(Qt::white);
+ painter.drawRect(shape.resizeHandle().adjusted(0, 0, -1, -1));
+
+ // paint the shape name
+ painter.setBrush(pal.text());
+ if (shape.type() == Shape::Triangle)
+ rect.adjust(0, rect.height()/2, 0, 0);
+ painter.drawText(rect, Qt::AlignCenter, shape.name());
+ }
+}
+
+void Document::setCurrentShape(int index)
+{
+ QString currentName;
+
+ if (m_currentIndex != -1)
+ update(m_shapeList.at(m_currentIndex).rect());
+
+ m_currentIndex = index;
+
+ if (m_currentIndex != -1) {
+ const Shape &current = m_shapeList.at(m_currentIndex);
+ update(current.rect());
+ currentName = current.name();
+ }
+
+ emit currentShapeChanged(currentName);
+}
+
+int Document::indexOf(const QString &shapeName) const
+{
+ for (int i = 0; i < m_shapeList.count(); ++i) {
+ if (m_shapeList.at(i).name() == shapeName)
+ return i;
+ }
+ return -1;
+}
+
+QString Document::uniqueName(const QString &name) const
+{
+ QString unique;
+
+ for (int i = 0; ; ++i) {
+ unique = name;
+ if (i > 0)
+ unique += QString::number(i);
+ if (indexOf(unique) == -1)
+ break;
+ }
+
+ return unique;
+}
+
+QString Document::currentShapeName() const
+{
+ if (m_currentIndex == -1)
+ return QString();
+ return m_shapeList.at(m_currentIndex).name();
+}
+
diff --git a/demos/undo/document.h b/demos/undo/document.h
new file mode 100644
index 0000000..0b12ad0
--- /dev/null
+++ b/demos/undo/document.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DOCUMENT_H
+#define DOCUMENT_H
+
+#include <QWidget>
+
+QT_FORWARD_DECLARE_CLASS(QUndoStack)
+QT_FORWARD_DECLARE_CLASS(QTextStream)
+
+class Shape
+{
+public:
+ enum Type { Rectangle, Circle, Triangle };
+
+ Shape(Type type = Rectangle, const QColor &color = Qt::red, const QRect &rect = QRect());
+
+ Type type() const;
+ QString name() const;
+ QRect rect() const;
+ QRect resizeHandle() const;
+ QColor color() const;
+
+ static QString typeToString(Type type);
+ static Type stringToType(const QString &s, bool *ok = 0);
+
+ static const QSize minSize;
+
+private:
+ Type m_type;
+ QRect m_rect;
+ QColor m_color;
+ QString m_name;
+
+ friend class Document;
+};
+
+class Document : public QWidget
+{
+ Q_OBJECT
+
+public:
+ Document(QWidget *parent = 0);
+
+ QString addShape(const Shape &shape);
+ void deleteShape(const QString &shapeName);
+ Shape shape(const QString &shapeName) const;
+ QString currentShapeName() const;
+
+ void setShapeRect(const QString &shapeName, const QRect &rect);
+ void setShapeColor(const QString &shapeName, const QColor &color);
+
+ bool load(QTextStream &stream);
+ void save(QTextStream &stream);
+
+ QString fileName() const;
+ void setFileName(const QString &fileName);
+
+ QUndoStack *undoStack() const;
+
+signals:
+ void currentShapeChanged(const QString &shapeName);
+
+protected:
+ void paintEvent(QPaintEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+
+private:
+ void setCurrentShape(int index);
+ int indexOf(const QString &shapeName) const;
+ int indexAt(const QPoint &pos) const;
+ QString uniqueName(const QString &name) const;
+
+ QList<Shape> m_shapeList;
+ int m_currentIndex;
+ int m_mousePressIndex;
+ QPoint m_mousePressOffset;
+ bool m_resizeHandlePressed;
+ QString m_fileName;
+
+ QUndoStack *m_undoStack;
+};
+
+#endif // DOCUMENT_H
diff --git a/demos/undo/icons/background.png b/demos/undo/icons/background.png
new file mode 100644
index 0000000..3bc5ed8
--- /dev/null
+++ b/demos/undo/icons/background.png
Binary files differ
diff --git a/demos/undo/icons/blue.png b/demos/undo/icons/blue.png
new file mode 100644
index 0000000..4e181bb
--- /dev/null
+++ b/demos/undo/icons/blue.png
Binary files differ
diff --git a/demos/undo/icons/circle.png b/demos/undo/icons/circle.png
new file mode 100644
index 0000000..ed16c6e
--- /dev/null
+++ b/demos/undo/icons/circle.png
Binary files differ
diff --git a/demos/undo/icons/exit.png b/demos/undo/icons/exit.png
new file mode 100644
index 0000000..539cb2e
--- /dev/null
+++ b/demos/undo/icons/exit.png
Binary files differ
diff --git a/demos/undo/icons/fileclose.png b/demos/undo/icons/fileclose.png
new file mode 100644
index 0000000..c5483d1
--- /dev/null
+++ b/demos/undo/icons/fileclose.png
Binary files differ
diff --git a/demos/undo/icons/filenew.png b/demos/undo/icons/filenew.png
new file mode 100644
index 0000000..57e57e3
--- /dev/null
+++ b/demos/undo/icons/filenew.png
Binary files differ
diff --git a/demos/undo/icons/fileopen.png b/demos/undo/icons/fileopen.png
new file mode 100644
index 0000000..33e0d63
--- /dev/null
+++ b/demos/undo/icons/fileopen.png
Binary files differ
diff --git a/demos/undo/icons/filesave.png b/demos/undo/icons/filesave.png
new file mode 100644
index 0000000..57fd5e2
--- /dev/null
+++ b/demos/undo/icons/filesave.png
Binary files differ
diff --git a/demos/undo/icons/green.png b/demos/undo/icons/green.png
new file mode 100644
index 0000000..e2e7cc9
--- /dev/null
+++ b/demos/undo/icons/green.png
Binary files differ
diff --git a/demos/undo/icons/ok.png b/demos/undo/icons/ok.png
new file mode 100644
index 0000000..e355ea9
--- /dev/null
+++ b/demos/undo/icons/ok.png
Binary files differ
diff --git a/demos/undo/icons/rectangle.png b/demos/undo/icons/rectangle.png
new file mode 100644
index 0000000..3a7d979
--- /dev/null
+++ b/demos/undo/icons/rectangle.png
Binary files differ
diff --git a/demos/undo/icons/red.png b/demos/undo/icons/red.png
new file mode 100644
index 0000000..58c3e72
--- /dev/null
+++ b/demos/undo/icons/red.png
Binary files differ
diff --git a/demos/undo/icons/redo.png b/demos/undo/icons/redo.png
new file mode 100644
index 0000000..5591517
--- /dev/null
+++ b/demos/undo/icons/redo.png
Binary files differ
diff --git a/demos/undo/icons/remove.png b/demos/undo/icons/remove.png
new file mode 100644
index 0000000..7a7b048
--- /dev/null
+++ b/demos/undo/icons/remove.png
Binary files differ
diff --git a/demos/undo/icons/triangle.png b/demos/undo/icons/triangle.png
new file mode 100644
index 0000000..2969131
--- /dev/null
+++ b/demos/undo/icons/triangle.png
Binary files differ
diff --git a/demos/undo/icons/undo.png b/demos/undo/icons/undo.png
new file mode 100644
index 0000000..8cf63a8
--- /dev/null
+++ b/demos/undo/icons/undo.png
Binary files differ
diff --git a/demos/undo/main.cpp b/demos/undo/main.cpp
new file mode 100644
index 0000000..f36a6e8
--- /dev/null
+++ b/demos/undo/main.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include "mainwindow.h"
+
+int main(int argc, char **argv)
+{
+ Q_INIT_RESOURCE(undo);
+
+ QApplication app(argc, argv);
+
+ MainWindow win;
+ win.resize(800, 600);
+ win.show();
+
+ return app.exec();
+};
diff --git a/demos/undo/mainwindow.cpp b/demos/undo/mainwindow.cpp
new file mode 100644
index 0000000..409fd14
--- /dev/null
+++ b/demos/undo/mainwindow.cpp
@@ -0,0 +1,446 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QUndoGroup>
+#include <QUndoStack>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QTextStream>
+#include <QToolButton>
+#include "document.h"
+#include "mainwindow.h"
+#include "commands.h"
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+{
+ setupUi(this);
+
+ QWidget *w = documentTabs->widget(0);
+ documentTabs->removeTab(0);
+ delete w;
+
+ connect(actionOpen, SIGNAL(triggered()), this, SLOT(openDocument()));
+ connect(actionClose, SIGNAL(triggered()), this, SLOT(closeDocument()));
+ connect(actionNew, SIGNAL(triggered()), this, SLOT(newDocument()));
+ connect(actionSave, SIGNAL(triggered()), this, SLOT(saveDocument()));
+ connect(actionExit, SIGNAL(triggered()), this, SLOT(close()));
+ connect(actionRed, SIGNAL(triggered()), this, SLOT(setShapeColor()));
+ connect(actionGreen, SIGNAL(triggered()), this, SLOT(setShapeColor()));
+ connect(actionBlue, SIGNAL(triggered()), this, SLOT(setShapeColor()));
+ connect(actionAddCircle, SIGNAL(triggered()), this, SLOT(addShape()));
+ connect(actionAddRectangle, SIGNAL(triggered()), this, SLOT(addShape()));
+ connect(actionAddTriangle, SIGNAL(triggered()), this, SLOT(addShape()));
+ connect(actionRemoveShape, SIGNAL(triggered()), this, SLOT(removeShape()));
+ connect(actionAddRobot, SIGNAL(triggered()), this, SLOT(addRobot()));
+ connect(actionAddSnowman, SIGNAL(triggered()), this, SLOT(addSnowman()));
+ connect(actionAbout, SIGNAL(triggered()), this, SLOT(about()));
+ connect(actionAboutQt, SIGNAL(triggered()), this, SLOT(aboutQt()));
+
+ connect(undoLimit, SIGNAL(valueChanged(int)), this, SLOT(updateActions()));
+ connect(documentTabs, SIGNAL(currentChanged(int)), this, SLOT(updateActions()));
+
+ actionOpen->setShortcut(QString("Ctrl+O"));
+ actionClose->setShortcut(QString("Ctrl+W"));
+ actionNew->setShortcut(QString("Ctrl+N"));
+ actionSave->setShortcut(QString("Ctrl+S"));
+ actionExit->setShortcut(QString("Ctrl+Q"));
+ actionRemoveShape->setShortcut(QString("Del"));
+ actionRed->setShortcut(QString("Alt+R"));
+ actionGreen->setShortcut(QString("Alt+G"));
+ actionBlue->setShortcut(QString("Alt+B"));
+ actionAddCircle->setShortcut(QString("Alt+C"));
+ actionAddRectangle->setShortcut(QString("Alt+L"));
+ actionAddTriangle->setShortcut(QString("Alt+T"));
+
+ m_undoGroup = new QUndoGroup(this);
+ undoView->setGroup(m_undoGroup);
+ undoView->setCleanIcon(QIcon(":/icons/ok.png"));
+
+ QAction *undoAction = m_undoGroup->createUndoAction(this);
+ QAction *redoAction = m_undoGroup->createRedoAction(this);
+ undoAction->setIcon(QIcon(":/icons/undo.png"));
+ redoAction->setIcon(QIcon(":/icons/redo.png"));
+ menuShape->insertAction(menuShape->actions().at(0), undoAction);
+ menuShape->insertAction(undoAction, redoAction);
+
+ toolBar->addAction(undoAction);
+ toolBar->addAction(redoAction);
+
+ newDocument();
+ updateActions();
+};
+
+void MainWindow::updateActions()
+{
+ Document *doc = currentDocument();
+ m_undoGroup->setActiveStack(doc == 0 ? 0 : doc->undoStack());
+ QString shapeName = doc == 0 ? QString() : doc->currentShapeName();
+
+ actionAddRobot->setEnabled(doc != 0);
+ actionAddSnowman->setEnabled(doc != 0);
+ actionAddCircle->setEnabled(doc != 0);
+ actionAddRectangle->setEnabled(doc != 0);
+ actionAddTriangle->setEnabled(doc != 0);
+ actionClose->setEnabled(doc != 0);
+ actionSave->setEnabled(doc != 0 && !doc->undoStack()->isClean());
+ undoLimit->setEnabled(doc != 0 && doc->undoStack()->count() == 0);
+
+ if (shapeName.isEmpty()) {
+ actionRed->setEnabled(false);
+ actionGreen->setEnabled(false);
+ actionBlue->setEnabled(false);
+ actionRemoveShape->setEnabled(false);
+ } else {
+ Shape shape = doc->shape(shapeName);
+ actionRed->setEnabled(shape.color() != Qt::red);
+ actionGreen->setEnabled(shape.color() != Qt::green);
+ actionBlue->setEnabled(shape.color() != Qt::blue);
+ actionRemoveShape->setEnabled(true);
+ }
+
+ if (doc != 0) {
+ int index = documentTabs->indexOf(doc);
+ Q_ASSERT(index != -1);
+ static const QIcon unsavedIcon(":/icons/filesave.png");
+ documentTabs->setTabIcon(index, doc->undoStack()->isClean() ? QIcon() : unsavedIcon);
+
+ if (doc->undoStack()->count() == 0)
+ doc->undoStack()->setUndoLimit(undoLimit->value());
+ }
+}
+
+void MainWindow::openDocument()
+{
+ QString fileName = QFileDialog::getOpenFileName(this);
+ if (fileName.isEmpty())
+ return;
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly)) {
+ QMessageBox::warning(this,
+ tr("File error"),
+ tr("Failed to open\n%1").arg(fileName));
+ return;
+ }
+ QTextStream stream(&file);
+
+ Document *doc = new Document();
+ if (!doc->load(stream)) {
+ QMessageBox::warning(this,
+ tr("Parse error"),
+ tr("Failed to parse\n%1").arg(fileName));
+ delete doc;
+ return;
+ }
+
+ doc->setFileName(fileName);
+ addDocument(doc);
+}
+
+QString MainWindow::fixedWindowTitle(const Document *doc) const
+{
+ QString title = doc->fileName();
+
+ if (title.isEmpty())
+ title = tr("Unnamed");
+ else
+ title = QFileInfo(title).fileName();
+
+ QString result;
+
+ for (int i = 0; ; ++i) {
+ result = title;
+ if (i > 0)
+ result += QString::number(i);
+
+ bool unique = true;
+ for (int j = 0; j < documentTabs->count(); ++j) {
+ const QWidget *widget = documentTabs->widget(j);
+ if (widget == doc)
+ continue;
+ if (result == documentTabs->tabText(j)) {
+ unique = false;
+ break;
+ }
+ }
+
+ if (unique)
+ break;
+ }
+
+ return result;
+}
+
+void MainWindow::addDocument(Document *doc)
+{
+ if (documentTabs->indexOf(doc) != -1)
+ return;
+ m_undoGroup->addStack(doc->undoStack());
+ documentTabs->addTab(doc, fixedWindowTitle(doc));
+ connect(doc, SIGNAL(currentShapeChanged(QString)), this, SLOT(updateActions()));
+ connect(doc->undoStack(), SIGNAL(indexChanged(int)), this, SLOT(updateActions()));
+ connect(doc->undoStack(), SIGNAL(cleanChanged(bool)), this, SLOT(updateActions()));
+
+ setCurrentDocument(doc);
+}
+
+void MainWindow::setCurrentDocument(Document *doc)
+{
+ documentTabs->setCurrentWidget(doc);
+}
+
+Document *MainWindow::currentDocument() const
+{
+ return qobject_cast<Document*>(documentTabs->currentWidget());
+}
+
+void MainWindow::removeDocument(Document *doc)
+{
+ int index = documentTabs->indexOf(doc);
+ if (index == -1)
+ return;
+
+ documentTabs->removeTab(index);
+ m_undoGroup->removeStack(doc->undoStack());
+ disconnect(doc, SIGNAL(currentShapeChanged(QString)), this, SLOT(updateActions()));
+ disconnect(doc->undoStack(), SIGNAL(indexChanged(int)), this, SLOT(updateActions()));
+ disconnect(doc->undoStack(), SIGNAL(cleanChanged(bool)), this, SLOT(updateActions()));
+
+ if (documentTabs->count() == 0) {
+ newDocument();
+ updateActions();
+ }
+}
+
+void MainWindow::saveDocument()
+{
+ Document *doc = currentDocument();
+ if (doc == 0)
+ return;
+
+ for (;;) {
+ QString fileName = doc->fileName();
+
+ if (fileName.isEmpty())
+ fileName = QFileDialog::getSaveFileName(this);
+ if (fileName.isEmpty())
+ break;
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly)) {
+ QMessageBox::warning(this,
+ tr("File error"),
+ tr("Failed to open\n%1").arg(fileName));
+ doc->setFileName(QString());
+ } else {
+ QTextStream stream(&file);
+ doc->save(stream);
+ doc->setFileName(fileName);
+
+ int index = documentTabs->indexOf(doc);
+ Q_ASSERT(index != -1);
+ documentTabs->setTabText(index, fixedWindowTitle(doc));
+
+ break;
+ }
+ }
+}
+
+void MainWindow::closeDocument()
+{
+ Document *doc = currentDocument();
+ if (doc == 0)
+ return;
+
+ if (!doc->undoStack()->isClean()) {
+ int button
+ = QMessageBox::warning(this,
+ tr("Unsaved changes"),
+ tr("Would you like to save this document?"),
+ QMessageBox::Yes, QMessageBox::No);
+ if (button == QMessageBox::Yes)
+ saveDocument();
+ }
+
+ removeDocument(doc);
+ delete doc;
+}
+
+void MainWindow::newDocument()
+{
+ addDocument(new Document());
+}
+
+static QColor randomColor()
+{
+ int r = (int) (3.0*(rand()/(RAND_MAX + 1.0)));
+ switch (r) {
+ case 0:
+ return Qt::red;
+ case 1:
+ return Qt::green;
+ default:
+ break;
+ }
+ return Qt::blue;
+}
+
+static QRect randomRect(const QSize &s)
+{
+ QSize min = Shape::minSize;
+
+ int left = (int) ((0.0 + s.width() - min.width())*(rand()/(RAND_MAX + 1.0)));
+ int top = (int) ((0.0 + s.height() - min.height())*(rand()/(RAND_MAX + 1.0)));
+ int width = (int) ((0.0 + s.width() - left - min.width())*(rand()/(RAND_MAX + 1.0))) + min.width();
+ int height = (int) ((0.0 + s.height() - top - min.height())*(rand()/(RAND_MAX + 1.0))) + min.height();
+
+ return QRect(left, top, width, height);
+}
+
+void MainWindow::addShape()
+{
+ Document *doc = currentDocument();
+ if (doc == 0)
+ return;
+
+ Shape::Type type;
+
+ if (sender() == actionAddCircle)
+ type = Shape::Circle;
+ else if (sender() == actionAddRectangle)
+ type = Shape::Rectangle;
+ else if (sender() == actionAddTriangle)
+ type = Shape::Triangle;
+ else return;
+
+ Shape newShape(type, randomColor(), randomRect(doc->size()));
+ doc->undoStack()->push(new AddShapeCommand(doc, newShape));
+}
+
+void MainWindow::removeShape()
+{
+ Document *doc = currentDocument();
+ if (doc == 0)
+ return;
+
+ QString shapeName = doc->currentShapeName();
+ if (shapeName.isEmpty())
+ return;
+
+ doc->undoStack()->push(new RemoveShapeCommand(doc, shapeName));
+}
+
+void MainWindow::setShapeColor()
+{
+ Document *doc = currentDocument();
+ if (doc == 0)
+ return;
+
+ QString shapeName = doc->currentShapeName();
+ if (shapeName.isEmpty())
+ return;
+
+ QColor color;
+
+ if (sender() == actionRed)
+ color = Qt::red;
+ else if (sender() == actionGreen)
+ color = Qt::green;
+ else if (sender() == actionBlue)
+ color = Qt::blue;
+ else
+ return;
+
+ if (color == doc->shape(shapeName).color())
+ return;
+
+ doc->undoStack()->push(new SetShapeColorCommand(doc, shapeName, color));
+}
+
+void MainWindow::addSnowman()
+{
+ Document *doc = currentDocument();
+ if (doc == 0)
+ return;
+
+ // Create a macro command using beginMacro() and endMacro()
+
+ doc->undoStack()->beginMacro(tr("Add snowman"));
+ doc->undoStack()->push(new AddShapeCommand(doc,
+ Shape(Shape::Circle, Qt::blue, QRect(51, 30, 97, 95))));
+ doc->undoStack()->push(new AddShapeCommand(doc,
+ Shape(Shape::Circle, Qt::blue, QRect(27, 123, 150, 133))));
+ doc->undoStack()->push(new AddShapeCommand(doc,
+ Shape(Shape::Circle, Qt::blue, QRect(11, 253, 188, 146))));
+ doc->undoStack()->endMacro();
+}
+
+void MainWindow::addRobot()
+{
+ Document *doc = currentDocument();
+ if (doc == 0)
+ return;
+
+ // Compose a macro command by explicitly adding children to a parent command
+
+ QUndoCommand *parent = new QUndoCommand(tr("Add robot"));
+
+ new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(115, 15, 81, 70)), parent);
+ new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(82, 89, 148, 188)), parent);
+ new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(76, 280, 80, 165)), parent);
+ new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(163, 280, 80, 164)), parent);
+ new AddShapeCommand(doc, Shape(Shape::Circle, Qt::blue, QRect(116, 25, 80, 50)), parent);
+ new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(232, 92, 80, 127)), parent);
+ new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(2, 92, 80, 125)), parent);
+
+ doc->undoStack()->push(parent);
+}
+
+void MainWindow::about()
+{
+ QMessageBox::about(this, tr("About Undo"), tr("The Undo demonstration shows how to use the Qt Undo framework."));
+}
+
+void MainWindow::aboutQt()
+{
+ QMessageBox::aboutQt(this, tr("About Qt"));
+}
diff --git a/demos/undo/mainwindow.h b/demos/undo/mainwindow.h
new file mode 100644
index 0000000..5340e94
--- /dev/null
+++ b/demos/undo/mainwindow.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include "ui_mainwindow.h"
+
+class Document;
+
+class MainWindow : public QMainWindow, public Ui::MainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = 0);
+
+ void addDocument(Document *doc);
+ void removeDocument(Document *doc);
+ void setCurrentDocument(Document *doc);
+ Document *currentDocument() const;
+
+public slots:
+ void openDocument();
+ void saveDocument();
+ void closeDocument();
+ void newDocument();
+
+ void addShape();
+ void removeShape();
+ void setShapeColor();
+
+ void addSnowman();
+ void addRobot();
+
+ void about();
+ void aboutQt();
+
+private slots:
+ void updateActions();
+
+private:
+ QUndoGroup *m_undoGroup;
+
+ QString fixedWindowTitle(const Document *doc) const;
+};
+
+#endif // MAINWINDOW_H
diff --git a/demos/undo/mainwindow.ui b/demos/undo/mainwindow.ui
new file mode 100644
index 0000000..91a0b43
--- /dev/null
+++ b/demos/undo/mainwindow.ui
@@ -0,0 +1,322 @@
+<ui version="4.0" >
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>567</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="iconSize" >
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <widget class="QWidget" name="centralwidget" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QTabWidget" name="documentTabs" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab" >
+ <attribute name="title" >
+ <string>Tab 1</string>
+ </attribute>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>567</width>
+ <height>27</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menuFile" >
+ <property name="title" >
+ <string>File</string>
+ </property>
+ <addaction name="actionNew" />
+ <addaction name="actionOpen" />
+ <addaction name="actionSave" />
+ <addaction name="actionClose" />
+ <addaction name="separator" />
+ <addaction name="actionExit" />
+ </widget>
+ <widget class="QMenu" name="menuShape" >
+ <property name="title" >
+ <string>Edit</string>
+ </property>
+ <widget class="QMenu" name="menuMacros" >
+ <property name="title" >
+ <string>Macros</string>
+ </property>
+ <addaction name="actionAddRobot" />
+ <addaction name="actionAddSnowman" />
+ </widget>
+ <addaction name="separator" />
+ <addaction name="actionAddCircle" />
+ <addaction name="actionAddRectangle" />
+ <addaction name="actionAddTriangle" />
+ <addaction name="actionRemoveShape" />
+ <addaction name="separator" />
+ <addaction name="actionRed" />
+ <addaction name="actionGreen" />
+ <addaction name="actionBlue" />
+ <addaction name="separator" />
+ <addaction name="menuMacros" />
+ </widget>
+ <widget class="QMenu" name="menuHelp" >
+ <property name="title" >
+ <string>Help</string>
+ </property>
+ <addaction name="actionAbout" />
+ <addaction name="actionAboutQt" />
+ </widget>
+ <addaction name="menuFile" />
+ <addaction name="menuShape" />
+ <addaction name="menuHelp" />
+ </widget>
+ <widget class="QStatusBar" name="statusbar" />
+ <widget class="QToolBar" name="toolBar" >
+ <property name="windowTitle" >
+ <string>File actions</string>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <attribute name="toolBarArea" >
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak" >
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionNew" />
+ <addaction name="actionOpen" />
+ <addaction name="actionSave" />
+ <addaction name="actionClose" />
+ <addaction name="separator" />
+ </widget>
+ <widget class="QToolBar" name="shapeToolBar" >
+ <property name="windowTitle" >
+ <string>Shape actions</string>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <attribute name="toolBarArea" >
+ <enum>LeftToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak" >
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionAddRectangle" />
+ <addaction name="actionAddCircle" />
+ <addaction name="actionAddTriangle" />
+ <addaction name="actionRemoveShape" />
+ <addaction name="separator" />
+ <addaction name="actionRed" />
+ <addaction name="actionGreen" />
+ <addaction name="actionBlue" />
+ </widget>
+ <widget class="QDockWidget" name="dockWidget" >
+ <property name="windowTitle" >
+ <string>Undo Stack</string>
+ </property>
+ <attribute name="dockWidgetArea" >
+ <number>2</number>
+ </attribute>
+ <widget class="QWidget" name="dockWidgetContents" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>4</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Undo limit</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="undoLimit" />
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QUndoView" name="undoView" >
+ <property name="alternatingRowColors" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <action name="actionOpen" >
+ <property name="icon" >
+ <iconset resource="undo.qrc" >:/icons/fileopen.png</iconset>
+ </property>
+ <property name="text" >
+ <string>&amp;Open</string>
+ </property>
+ </action>
+ <action name="actionClose" >
+ <property name="icon" >
+ <iconset resource="undo.qrc" >:/icons/fileclose.png</iconset>
+ </property>
+ <property name="text" >
+ <string>&amp;Close</string>
+ </property>
+ </action>
+ <action name="actionNew" >
+ <property name="icon" >
+ <iconset resource="undo.qrc" >:/icons/filenew.png</iconset>
+ </property>
+ <property name="text" >
+ <string>&amp;New</string>
+ </property>
+ </action>
+ <action name="actionSave" >
+ <property name="icon" >
+ <iconset resource="undo.qrc" >:/icons/filesave.png</iconset>
+ </property>
+ <property name="text" >
+ <string>&amp;Save</string>
+ </property>
+ </action>
+ <action name="actionExit" >
+ <property name="icon" >
+ <iconset resource="undo.qrc" >:/icons/exit.png</iconset>
+ </property>
+ <property name="text" >
+ <string>E&amp;xit</string>
+ </property>
+ </action>
+ <action name="actionRed" >
+ <property name="icon" >
+ <iconset resource="undo.qrc" >:/icons/red.png</iconset>
+ </property>
+ <property name="text" >
+ <string>Red</string>
+ </property>
+ </action>
+ <action name="actionGreen" >
+ <property name="icon" >
+ <iconset resource="undo.qrc" >:/icons/green.png</iconset>
+ </property>
+ <property name="text" >
+ <string>Green</string>
+ </property>
+ </action>
+ <action name="actionBlue" >
+ <property name="icon" >
+ <iconset resource="undo.qrc" >:/icons/blue.png</iconset>
+ </property>
+ <property name="text" >
+ <string>Blue</string>
+ </property>
+ </action>
+ <action name="actionAddRectangle" >
+ <property name="icon" >
+ <iconset resource="undo.qrc" >:/icons/rectangle.png</iconset>
+ </property>
+ <property name="text" >
+ <string>Add Rectangle</string>
+ </property>
+ </action>
+ <action name="actionAddCircle" >
+ <property name="icon" >
+ <iconset resource="undo.qrc" >:/icons/circle.png</iconset>
+ </property>
+ <property name="text" >
+ <string>Add Circle</string>
+ </property>
+ </action>
+ <action name="actionRemoveShape" >
+ <property name="icon" >
+ <iconset resource="undo.qrc" >:/icons/remove.png</iconset>
+ </property>
+ <property name="text" >
+ <string>Remove Shape</string>
+ </property>
+ </action>
+ <action name="actionAddRobot" >
+ <property name="text" >
+ <string>Add robot</string>
+ </property>
+ </action>
+ <action name="actionAddSnowman" >
+ <property name="text" >
+ <string>Add snowan</string>
+ </property>
+ </action>
+ <action name="actionAddTriangle" >
+ <property name="icon" >
+ <iconset resource="undo.qrc" >:/icons/triangle.png</iconset>
+ </property>
+ <property name="text" >
+ <string>addTriangle</string>
+ </property>
+ </action>
+ <action name="actionAbout" >
+ <property name="text" >
+ <string>About</string>
+ </property>
+ </action>
+ <action name="actionAboutQt" >
+ <property name="text" >
+ <string>About Qt</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QUndoView</class>
+ <extends>QListView</extends>
+ <header>qundoview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="undo.qrc" />
+ </resources>
+ <connections/>
+</ui>
diff --git a/demos/undo/undo.pro b/demos/undo/undo.pro
new file mode 100644
index 0000000..bf7017b
--- /dev/null
+++ b/demos/undo/undo.pro
@@ -0,0 +1,19 @@
+SOURCES += main.cpp mainwindow.cpp commands.cpp document.cpp
+HEADERS += mainwindow.h commands.h document.h
+FORMS += mainwindow.ui
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+RESOURCES += undo.qrc
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/undo
+sources.files = $$SOURCES $$HEADERS *.pro icons $$RESOURCES $$FORMS
+sources.path = $$[QT_INSTALL_DEMOS]/undo
+INSTALLS += target sources
+
+include($$QT_SOURCE_TREE/demos/demobase.pri)
+
diff --git a/demos/undo/undo.qrc b/demos/undo/undo.qrc
new file mode 100644
index 0000000..65619b8
--- /dev/null
+++ b/demos/undo/undo.qrc
@@ -0,0 +1,20 @@
+<RCC>
+ <qresource prefix="/" >
+ <file>icons/background.png</file>
+ <file>icons/blue.png</file>
+ <file>icons/circle.png</file>
+ <file>icons/exit.png</file>
+ <file>icons/fileclose.png</file>
+ <file>icons/filenew.png</file>
+ <file>icons/fileopen.png</file>
+ <file>icons/filesave.png</file>
+ <file>icons/green.png</file>
+ <file>icons/ok.png</file>
+ <file>icons/rectangle.png</file>
+ <file>icons/red.png</file>
+ <file>icons/redo.png</file>
+ <file>icons/remove.png</file>
+ <file>icons/triangle.png</file>
+ <file>icons/undo.png</file>
+ </qresource>
+</RCC>